60

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."

VansFannel
  • 45,055
  • 107
  • 359
  • 626
Zack Peterson
  • 56,055
  • 78
  • 209
  • 280

6 Answers6

138

Try to use

.Owner = Window.GetWindow(this)
slavoo
  • 5,798
  • 64
  • 37
  • 39
Martin Moser
  • 6,219
  • 1
  • 27
  • 41
48

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
Nir
  • 29,306
  • 10
  • 67
  • 103
  • 2
    Application.Current.MainWindow gave me exactly what I needed. I need to access the controls in the parent window from a child window opened using ShowDialog(). – D'Hag Mar 16 '12 at 18:22
10
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();
slavoo
  • 5,798
  • 64
  • 37
  • 39
JRL1283
  • 101
  • 1
  • 2
  • beware with this one. I had weird issues when running in `VMWare Fusion` on a `Macintosh` - window appeared for a sec then vanished. – itsho Feb 22 '16 at 15:21
  • Heads up: if you have another window (Splash window, etc.) displayed - you'll **must** set the `Owner` for it as well! otherwise you'll get some weird behaviors - your main window won't get `OnActivated` event / will stay in background / will suddenly vanish, etc. – itsho Mar 01 '16 at 14:15
5

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.

Andrew Barrett
  • 19,721
  • 4
  • 47
  • 52
  • When I use this technique, the CanExecute event isn't called for the reference from the UserControl. CanExecute seems to default to false, disabling the Element that the command is on (a context menuitem, in my case). A MenuItem in the parent window has no problems and is enabled. – Greg D Mar 05 '09 at 05:10
  • It has something to do with the command routing. My UserControl does not get focus, but has a context menu. If no Element is selected/focused when I try to view the UserControl's context menu, the command event isn't routed. – Greg D Mar 05 '09 at 06:31
  • If you want to post more info in a question I'll see if I can help you out. I use commands throughout the WPF app I'm making, and I'm really loving them at the moment. – Andrew Barrett Mar 05 '09 at 06:53
  • Thanks, Andrew. I _think_ I've figured it out, but I won't know 'til I try it. I believe I simply need to set CommandTarget="{Binding ElementName=This}" (This is the x:Name of the UserControl). That ought to source the command event from my usercontrol instead of whatever button has focus. :) – Greg D Mar 05 '09 at 13:03
  • Greg, I've updated, hopefully it might help you. Probably will need more info from you though to help you better. – Andrew Barrett Mar 05 '09 at 17:55
  • Thanks for the info, Andrew. :) I haven't had much time to look at it today yet. I'll throw a link here if/when I post a question. One diff is that my ContextMenu is on UserControl.ContextMenu and the UserControl is dynamically created/dropped into the Window. – Greg D Mar 05 '09 at 18:18
  • I've posted my question to: http://stackoverflow.com/questions/616206/wpf-usercontrol-and-commands-oh-my – Greg D Mar 05 '09 at 19:14
  • This breakes MVVM – Artfaith Nov 11 '19 at 06:00
0

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?

Zack Peterson
  • 56,055
  • 78
  • 209
  • 280
0

What about changing the name of the window to WindowMain1 or something, and setting the owner to that?

Davy8
  • 30,868
  • 25
  • 115
  • 173