1

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)

Thank you for any suggestion ..

Ash
  • 49
  • 1
  • 10
  • I haven't tried it on a ChildWindow but `MouseDragElementBehavior` with `ConstrainToParentBounds="True"` may be a quick and easy option. – Chris W. Aug 05 '14 at 14:17

1 Answers1

0

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:

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.

Hope I could help...

  • Hi, sorry for delayed response. I was able to get window back inside the screen when it was dragged out using above code. Thanks – Ash Aug 22 '14 at 16:21