简体   繁体   English

如何限制子窗口在父边界内的移动?

[英]How to limit child window's movement within parent boundaries?

I was wondering is it possible to limit child window's ability to be moved around to only within parent's panel boundaries ? 我想知道是否可以将子窗口的移动能力限制为仅在父面板的边界之内? Suppose I create a child window with a button click: 假设我通过单击按钮创建一个子窗口:

<UserControl x:Class="ChildWindowTest.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Child="clr-namespace:ChildWindowTest"
mc:Ignorable="d"             
d:DesignHeight="300" d:DesignWidth="400" >

<Grid x:Name="LayoutRoot" >
    <StackPanel Width="500" Height="500">
        <Button Width="100" Height="25" Click="Button_Click" Content="Child Window"/>
    </StackPanel>
</Grid>
</UserControl>

<controls:ChildWindow 
x:Class="ChildWindowTest.ChildWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
Width="400"     Height="300"    Title="ChildWindow1" >

<Grid x:Name="LayoutRoot" Margin="2">
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

</Grid>
</controls:ChildWindow>

I can move the generated child to left, right and down off screen (clipped off). 我可以将生成的孩子向左,向右和向下移出屏幕(关闭)。 I want to avoid that, basically set up a boundary within which child window is allowed to be moved (within StackPanel boundary) 我想避免这种情况,基本上是设置一个允许在其中移动子窗口的边界(在StackPanel边界内)

Thank you for any suggestion .. 谢谢你的任何建议..

I tried to keep my solution as simple as possible, but still it was quite challenging to achieve the desired behaviour. 我试图使我的解决方案尽可能简单,但是要实现所需的行为仍然是颇具挑战性的。

Basically, if you leave the ChildWindow's ControlTemplate alone, the following code should work for you: 基本上,如果您不理会ChildWindow的ControlTemplate,则以下代码将为您工作:

private void Button_Click(object sender, RoutedEventArgs e)
{
    ChildWindow wnd = new ChildWindow();
    wnd.Width = 800;
    wnd.Height = 600;
    wnd.Title = "Test";

    wnd.MouseLeftButtonUp += wnd_MouseLeftButtonUp;
    wnd.Loaded += wnd_Loaded;

    wnd.Show();
}

private void wnd_Loaded(object sender, RoutedEventArgs e)
{
    var wnd = sender as ChildWindow;
    myApplicationActualWidth = Application.Current.Host.Content.ActualWidth;
    myApplicationActualHeight = Application.Current.Host.Content.ActualHeight;

    //This call might be necessary to make sure the visual tree of wnd is constructed and can be inspected
    wnd.UpdateLayout();

    //wnd is guaranteed to have at least one child here
    myRoot = (FrameworkElement)VisualTreeHelper.GetChild(wnd, 0);
    myContentRoot = myRoot.FindName("ContentRoot") as FrameworkElement;

    //this is the title bar part
    myChrome = myRoot.FindName("Chrome") as FrameworkElement;
    myChrome.AddHandler(MouseLeftButtonUpEvent, new MouseButtonEventHandler(wnd_MouseLeftButtonUp), true);

    myTransform = (myContentRoot.RenderTransform as TransformGroup).Children.OfType<TranslateTransform>().First();
}

private void wnd_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    Point rootMousePosition = e.GetPosition(sender as ChildWindow);
    Point contentRootMousePosition = e.GetPosition(myContentRoot);
    Point currentOffset = new Point(rootMousePosition.X - contentRootMousePosition.X, rootMousePosition.Y - contentRootMousePosition.Y);
    TransformChildWindowToValidPosition(currentOffset);
}

private void TransformChildWindowToValidPosition(Point currentPosition)
{
    // handle left side
    if (currentPosition.X < 0)
    {
        myTransform.X = myTransform.X - currentPosition.X;
    }

    // handle top
    if (currentPosition.Y < 0)
    {
        myTransform.Y = myTransform.Y - currentPosition.Y;
    }

    // handle right side
    if (currentPosition.X + myContentRoot.ActualWidth > ActualWidth)
    {
        myTransform.X = myTransform.X - (currentPosition.X + myContentRoot.ActualWidth - myApplicationActualWidth);
    }

    // handle bottom
    if (currentPosition.Y + myContentRoot.ActualHeight > ActualHeight)
    {
        myTransform.Y = myTransform.Y - (currentPosition.Y + myContentRoot.ActualHeight - myApplicationActualHeight);
    }
}

private TranslateTransform myTransform;
private FrameworkElement myRoot;
private FrameworkElement myContentRoot;
private FrameworkElement myChrome;
private double myApplicationActualWidth;
private double myApplicationActualHeight;

This code basically does not allow you the move your ChildWindow outside the boundaries of the current SL application, but it should be a piece of cake to get your hands on the dimensions of the "parent" control of the window and readjust the values for all the edges. 这段代码基本上不允许您将ChildWindow移到当前SL应用程序的边界之外,但是要让您掌握窗口“父”控件的尺寸并重新调整所有值,这应该是小菜一碟边缘。

Hope I could help... 希望我能帮忙...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM