26
votes

I am using Window.ShowDialog() to open a modal window in my WPF (MVVM) application, but it lets me navigate to other windows using the Windows taskbar (Windows 7).

Consider this: I have 3 non-modal windows open in my application. Now One of these opens a modal window using Window.ShowDialog(). I also set Application.MainWindow as the owner of the modal window. This is so because I am using MVVM messaging and the message handler to open a new window is centralized in App.xaml.cs. The window does opens modally - no issues there. However, Windows 7 allows me to swtich to the other application windows from the taskbar. This leads to a situation where the modal window goes behind another window, which I prefer not to have.

I can't do anything on other windows as long as I have the modal open, but it would be nice if the modal window always remained on top as long as it's open. Is there a way I can disable taskbar switching when the modal is open? FYI - all open windows launched from the app appear as separate entries on the taskbar.

Thanks in advance!

5
Could we get some code from where you create the Window that becomes the modal dialog?user7116
What you needed was for the window to be above ALL other apps. What I need is for the window to be above any other window in the app, like a dialog window. For my requirements, these two lines: Owner = Application.Current.MainWindow; and ShowInTaskbar = false; works well. +1 for you.Fandi Susanto

5 Answers

63
votes

There isn't any code to base this off of, but it sounds like you have left off some properties on the Window you've created and expected ShowDialog to apply additional "dialog" semantics:

Window window = new Window()
{
    Title = "Modal Dialog",
    ShowInTaskbar = false,               // don't show the dialog on the taskbar
    Topmost = true,                      // ensure we're Always On Top
    ResizeMode = ResizeMode.NoResize,    // remove excess caption bar buttons
    Owner = Application.Current.MainWindow,
};

window.ShowDialog();
13
votes

Just set the owner property of the Window to the calling window. Then the activation of the WPF application in taskbar not just activates the MainWindow but also the modal child window and brings it to the front.

ChildWindow C = new ChildWindow();
C.Owner = this;
C.ShowDialog();
12
votes

Setting Topmost to True (Topmost=True) causes the dialog to be on the top of all windows in the system (not only in application).

So you can try to register the event Activated in your main window:

Activated += WindowActivated;

and activate an owner window of the modal dialog every time when another main window of your application become active.

private void WindowActivated(object sender, EventArgs e)
{
    Window window = Application.Current.Windows.OfType<YourMainWindow>().FirstOrDefault(p => p != this && !p.IsActive && p.OwnedWindows.Count > 0);
    if (window != null)
    {
        window.Activate();
    }
}

This simple hack assumes all your children windows are modal, but you can write a more sophisticated logic.

3
votes

I ended up using a combination of a couple of the answers here. The accepted answer was useful at first but as other people on here have pointed out setting Topmost = true means that the window is always above any other applications running. My solution was this:

var myWindow = new MyWindowType();
myWindow.Owner = Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);

I initially used:

myWindow.Owner = Application.Current.MainWindow;

However, this method causes problems if you have three windows open like this:

MainWindow
   |
   -----> ChildWindow1

               |
               ----->  ChildWindow2

Then setting ChildWindow2.Owner = Application.Current.MainWindow will set the owner of the window to be its grandparent window, not parent window.

To speed things up, I've added it as a code snippet in Visual Studio. If you add the following to Tools --> Code Snippet Manager --> My Code Snippets:

<CodeSnippets
    xmlns="http://schemas.microsoft.com/VisualStudio/2010/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>MVVM Set owner of page to be current active window</Title>
      <Shortcut>owner</Shortcut>
    </Header>
    <Snippet>
      <Code Language="CSharp">
        <![CDATA[System.Windows.Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

Typing 'owner' and double-tapping the tab key will add the 'Application.CurrentWindows...' part in for you automatically.

1
votes

Had to do a bit of modification. I had to set the owner and activate the window. Check for the pop up window and activate the window as given below.

        var enumerator = Application.Current.Windows.GetEnumerator();
        while (enumerator.MoveNext())
        {
            Window window = (Window)enumerator.Current;
            if (window != null && window.GetType() == typeof(PopUpWindow))
            {
                window.Activate();
            }
        }