1

I have a WPF configuration utility with a single window that runs during my WIX installer and can also be run independently after installation. SO contains solutions to bring the window to the front but they make it either always on top or the code returns immediately.

When the application starts, I want to bring the window to the front. Left to itself, it pops under my MSI dialog. I also want to let the user move other windows on top of it (it shouldn't be always on top), and I want to wait for the window to close in code. Perhaps I am being too picky as WPF does not appear to support this.

Currently, I have this:

MainWindow.Topmost = true;
MainWindow.Show();
MainWindow.Activate();
MainWindow.Topmost = false;
MainWindow.Focus();

It's great except that MainWindow.Show() returns immediately and execution resumes. In the past, we were using

MainWindow.TopMost = true;
MainWindow.ShowDialog();

But then this window is always on top and obstructs all other windows (not the best user experience). Are there any other options? Please feel free to suggest I am architecting this incorrectly as well. Thank you!

sirdank
  • 3,351
  • 3
  • 25
  • 58
  • *When the application starts, I want to bring it to the front. I also want to let the user move other windows on top of it (it shouldn't be always on top)*... that is the normal behaviour of a `Window` in WPF. *I want to wait for the window to close in code*... what is stopping that from happening? Perhaps you can explain your requirements a bit clearer? – Sheridan Jun 29 '15 at 12:57
  • @Sheridan I edited my question to reflect that my window pops under my MSI dialog when left to itself. – sirdank Jun 29 '15 at 13:01
  • [Parent](http://stackoverflow.com/q/9855954/1997232) problem? – Sinatr Jun 29 '15 at 13:01
  • @Sinatr I don't think it is. The WPF app runs through the installer by default but can also be run independently after installation. I don't believe I have anything to set as its parent in either situation. – sirdank Jun 29 '15 at 13:28
  • 1
    *app parent* is nonsense, I was thinking about multiple windows in same app. I was wrong. Your issue is more like [this](http://stackoverflow.com/q/5282588/1997232) one. – Sinatr Jun 29 '15 at 13:32
  • @Sinatr You are correct. The difficult arises because, as far as I can tell, there is no way to do this cleanly in WPF specifically (as opposed to windows forms). I am going to try out almulo's solution because it looks promising. – sirdank Jun 29 '15 at 13:35

2 Answers2

2

Can you modify the MainWindow code? If so, simply put this in its code-behind:

protected override void OnActivated(EventArgs e)
{
    base.OnActivated(e);

    this.Topmost = true;
    this.Topmost = false;
}

Then, no matter if you use .Show() or .ShowDialog(), every time the Window is activated, it'll move itself to the front.

EDIT: If you can't/won't modify MainWindow code, you can just do the same subscribing to the Activated event:

MainWindow.Activated += new EventHandler(window_Activated);
MainWindow.ShowDialog();  // or .Show()

...

void window_Activated(object sender, EventArgs e)
{
    var window = sender as MainWindow;

    window.Topmost = true;
    window.Topmost = false;
}
almulo
  • 4,918
  • 1
  • 20
  • 29
  • This is exactly what I wanted. It requires very little code change, is low-risk, and retains all the original functionality except the extreme desktop obstruction produced by setting `TopMost`. – sirdank Jun 29 '15 at 13:51
-2

Instead of using

MainWindow.ShowDialog();

you could override the Closing event of the window after using the code you had before:

    MainWindow.Topmost = true;
    MainWindow.Show();
    MainWindow.Activate();
    MainWindow.Topmost = false;
    MainWindow.Focus();
}

/// <summary>
/// Raises the <see cref="E:System.Windows.Window.Closing"/> event.
/// </summary>
/// <param name="e">A <see cref="T:System.ComponentModel.CancelEventArgs"/> that contains the event data.</param>
protected override void OnClosing(CancelEventArgs e)
{
    base.OnClosing(e);
}

EDIT:

In the closing event, you could use a callback (from the caller), to continue after closing this window.

Alternatively, you should check your installer window positioning and then calling

MainWindow.ShowDialog();

thus preventing the MainWindow being top most all the time. It will prevent execution of the caller until the MainWindow is closed.

EDIT 2: Using topmost is probably not the best idea, since it moves your dialog in front of any window (even the ones the user moved in front of your installer). Maybe you should add another custom action without additional windows?

Urutar
  • 67
  • 2
  • 7
  • 1
    Hi Urutar, I tried something similar to this but it seemed like a lot of testing would be required to guarantee it's providing the same functionality I wanted and it seemed like a hack. – sirdank Jun 29 '15 at 13:29
  • Maybe you could add another custom action? I'm not entirely familiar with the MSI, but that should be possible? – Urutar Jun 29 '15 at 13:33
  • That is possible but I also need to be able to run my WPF app independently of my installer. If I may, in a friendly spirit, offer some advice, while the changes you are suggesting may work, I think they'd be poor design introducing unneeded complexity. However, I did not downvote you so perhaps someone who did would be inclined to explain. – sirdank Jun 29 '15 at 14:04