WPF: How do I set the Owner Window of a Dialog shown by a UserControl?
.NetWpfvb.netDialogUser Controls.Net Problem Overview
I've got a WPF application with these three types of things...
- WindowMain
- UserControlZack
- WindowModal
UserControlZack1 sits on my WindowMain...
<Window x:Class="WindowMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ProjectName"
...
Name="WindowMain">
<Grid>
...
<local:UserControlZack x:Name="UserControlZack1" ... />
...
</Grid>
</Window>
UserControlZack1 displays a WindowModal dailog box...
Partial Public Class UserControlZack
...
Private Sub SomeButton_Click(...)
'instantiate the dialog box and open modally...
Dim box As WindowModal = New WindowModal()
box.Owner = ?????
box.ShowDialog()
'process data entered by user if dialog box is accepted...
If (box.DialogResult.GetValueOrDefault = True) Then
_SomeVar = box.SomeVar
...
End If
End Sub
End Class
How do I set box.Owner to the correct Window, my running instance of WindowMain?
I cannot use box.Owner = Me.Owner
, because "'Owner' is not a member of 'ProjectName.UserControlZack'."
I cannot use box.Owner = Me.Parent
, because that returns a Grid, not the Window.
I cannot use box.Owner = WindowMain
, because "'WindowMain' is a type and cannot be used as an expression."
.Net Solutions
Solution 1 - .Net
Try to use
.Owner = Window.GetWindow(this)
Solution 2 - .Net
To get the top level window your control is in, assuming there is one:
(Window)PresentationSource.FromVisual(this).RootVisual
To get the main window:
Application.Current.MainWindow
Solution 3 - .Net
MyWpfDialog dialog = new MyWpfDialog();
//remember, this is WinForms UserControl and its Handle property is
//actually IntPtr containing Win32 HWND.
new System.Windows.Interop.WindowInteropHelper(dialog).Owner = this.Handle;
dialog.ShowDialog();
Solution 4 - .Net
Updating to try and help Greg from the comments. The command works in the main windows menu, the button in the user control and the context menu in the user control.
I'd do it with commands. So have a class Commands.cs something like:
public static class Commands
{
public static RoutedUICommand TestShowDialogCommand = new RoutedUICommand("Test command", "TestShowDialog", typeof(Commands));
}
Register these in your main window: (you don't need the canshow it defaults to true)
public Window1()
{
InitializeComponent();
CommandManager.RegisterClassCommandBinding(typeof(System.Windows.Controls.Control),
new CommandBinding(Commands.TestShowDialogCommand, ShowDialogCommand, CanShowDialogCommand));
}
private void ShowDialogCommand(object sender, ExecutedRoutedEventArgs e)
{
var box = new Window();
box.Owner = this;
box.ShowDialog();
}
private void CanShowDialogCommand(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
This is my xaml for the main window:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication1="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="322">
<Grid>
<StackPanel>
<Menu>
<MenuItem Header="Test">
<MenuItem Header="ShowDialog" Command="{x:Static WpfApplication1:Commands.TestShowDialogCommand}"/>
</MenuItem>
</Menu>
<WpfApplication1:BazUserControl />
</StackPanel>
</Grid>
</Window>
This is the xaml for my user control (default code behind only)
<UserControl x:Class="WpfApplication1.BazUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication1="clr-namespace:WpfApplication1"
Height="300" Width="300">
<Grid>
<StackPanel>
<Button Command="{x:Static WpfApplication1:Commands.TestShowDialogCommand}" Content="ClickMe" ></Button>
<TextBox>
<TextBox.ContextMenu>
<ContextMenu>
<MenuItem Header="ShowDialog" Command="{x:Static WpfApplication1:Commands.TestShowDialogCommand}" />
</ContextMenu>
</TextBox.ContextMenu>
</TextBox>
</StackPanel>
</Grid>
</UserControl>
You could take it a bit further and handle the command in a controller class instead and make it that bit more MVC.
Solution 5 - .Net
I got it to work by crawling all the way back up through my XAML...
box.Owner = DirectCast(DirectCast(DirectCast(Me.Parent, Grid).Parent, Grid).Parent, Window)
But this seems quite inelegant. Is there a better way?
Solution 6 - .Net
What about changing the name of the window to WindowMain1 or something, and setting the owner to that?