Tuesday, November 04, 2008

MSDN Question on WPF: Moving child window along with parent window

I noticed quiet a few people have this requirement where a popped up window has to move along with the parent window. This could be done pretty easily, thanks to the data binding features of WPF. Though this post does not handle pop ups' in wpf, the idea could easily be extended to them. The idea is to bind the Left and Top parameters of the Window (child) to those of its parent.

The following shows a window named "ParentWindow" which has a button when clicked launches a "ChildWindow".

<Window x:Class="XamlDemystified.ParentWindow"   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="300" Width="300" Name="w"
>
<
StackPanel DataContext="{Binding ElementName=w}"
>
<
Button Click="Button_Click">Show</Button
>
</
StackPanel
>
</
Window>

The DataContext of the StackPanel is set the window instance itself, that too within the XAML.This has nothing to do with the current implementation but I wanted to shown how to set datacontext to the current instance of the window from XAML, instead of doing it from the C# code. If you have read my previous posts, you can notice that I usually set the DataContext from code-behind. Anyway, the Button_Click is shown below.

private void Button_Click(object sender, RoutedEventArgs e)
{
ChildWindow cW = new ChildWindow();
cW.Owner = this;
cW.Show();
cW.DataContext = this;
}

The event handler for the button click creates a new ChildWindow, sets its Owner as well as the DataContext to that of the parent. And there are different ways to do this, but I chose to do it the simplest way. The ChildWindow is shown below.




<Window x:Class="XamlDemystified.ChildWindow"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window4
" Height="100" Width="100"
Left="{Binding Left}"
Top="{Binding Top}"
Name="e"
>
<
Grid
>
<
Label Content="{Binding Left}"
/>
</
Grid
>
</
Window>


The child window contains a label that constantly displays the Left of the parent.



The solution is not fool-proof. It has certain limitations, the major one being the binding breaks when you move the child window. For this to work, you cannot move the child window manually. This could easily be fixed by handling the LocationChanged event and re-binding the Left and Top elements. If you do this, you also need to use a flag to determine if the LocationChanged was triggered by binding, in which case you ignore or if the user movement has caused this. I have not bothered to show the code, but if you do not get the idea, feel free to post it on MSDN Social forums for WPF or post a comment on this post. This being said, the ChildWindow size has to be less than that of the ParentWindow so that you can move the parent without having to touch the child window.



Alternatively, if you set initial position of the child window, then you can use the same idea to relatively set the Left and Top of the child. You might also want to take a look at the WindowStartupLocation enumeration on the Window class.

No comments: