26

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!

Aequitas
  • 1,875
  • 1
  • 19
  • 43
Pratz
  • 299
  • 1
  • 3
  • 5
  • Could we get some code from where you create the Window that becomes the modal dialog? – user7116 Jun 20 '11 at 21:10
  • 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 Jul 22 '15 at 07:01

5 Answers5

63

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();
user7116
  • 60,025
  • 16
  • 134
  • 166
  • You are a savior sixlettervariables! Topmost was what I was missing. Apologies for not posting code but you nailed it. Can't believe I missed it. Thanks again! – Pratz Jul 06 '11 at 00:04
  • To remove the caption buttons you need to set its `ResizeMode` to `NoResize` instead of the `WindowStyle`. A ToolWindow is not a dialog. – David Anderson May 08 '12 at 13:33
  • @DavidAnderson: sounds good, provided you don't care to resize the dialog. – user7116 May 08 '12 at 13:38
  • Yeah, that's a good point, but you can also use Win32 API to remove the caption buttons and maintain resizing ability, WPF still has some flaky things about it I guess. All just code though, so always a way to do something. – David Anderson May 08 '12 at 13:59
  • But System.Windows.Window.ShowDialog() does not accept any parameter. Why? – J Pollack Apr 10 '13 at 15:56
13

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();
Bitbauer
  • 131
  • 1
  • 2
12

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.

Amadeus Sánchez
  • 1,887
  • 1
  • 20
  • 29
koalix
  • 133
  • 2
  • 7
  • 1
    this should be the accepted answer: it seems the only way to keep the dialog window on top of the mainwindow after activating the application using the taskbar. It's a known problem: http://connect.microsoft.com/VisualStudio/feedback/details/474480/wpf-showdialog-and-owner – stijn Oct 11 '13 at 09:10
  • This works better from the codebehind of the dialog itself (using += on the event). That allows the main window to not care what the other windows are doing. – Grault Nov 24 '14 at 23:20
  • Oh, and activating the dialog while it's hidden (because I don't like to actually close it) makes the main window inoperable, so a check of IsVisible is in order. – Grault Nov 24 '14 at 23:24
3

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.

GrandMasterFlush
  • 5,857
  • 17
  • 73
  • 98
  • 1
    this one saved my life because I have set all the options mentioned by everyone and but never looked what mainwindow could be. your answer led to me to look into that – Dirty Developer Apr 13 '17 at 05:42
1

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();
            }
        }
DiAgo
  • 241
  • 3
  • 6