Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override handling of taskbar command "Close all Windows"

Tags:

c#

wpf

I have a WPF-application with multiple unrelated Windows, i.e. there is always one MainWindow and optionally many others with no owner. If these windows get grouped in the taskbar, windows will provide the action "Close all Windows" in the taskbar context menu. If it is clicked, each Window of my application gets an individual close-command in an order I cannot control.

Problem: Some of my windows may ask before closing, if it's okay to cancel pending changes. This is annoying and confusing if there are many of those.

What I want is: If the MainWindow is asked for closing, I want to prompt once, if that's ok. If yes, all windows should close silently, otherwise stay open. But my MainWindow is not the first one, to process the closing procedure.

I have already found out, that I probably need to check the Windows Message Loop of my MainWindow for some WM_SYSCOMMAND with wparam SC_CLOSE. (see How can I distinguish between "Close All Windows" and "Close" individual windows in MFC with Windows 7?)

But how can I evaluate this, before I execute the closing-routine for any other window? ComponentDispatcher.ThreadPreprocessMessage in my mainwindow comes too late, it fires after some other window has started the closing procedure.

This question is somehow related to this one: Odd form closing behavior when using taskbar's Close All Windows

like image 607
Simon D. Avatar asked Oct 26 '15 15:10

Simon D.


1 Answers

Personally, I would just leave things as they are. I can see how having several prompts to save/cancel changes could be annoying, but it doesn't seem confusing to me. And while annoying, it seems like a minor annoyance, and frankly one that might teach the user to not use the "Close all windows" option when they have left a bunch of these windows open. That said…


As the question you've found points out, there is no built-in way to distinguish the "Close all windows" from a regular "Close window" command. The system is simply sending the messages to the windows in sequence.

In MFC (i.e. the context of the other question), you can call AfxGetCurrentMessage() to retrieve information about what actually instigated the SC_CLOSE message. If it was user input that was translated to a close command, there will be some type of user input (keyboard, mouse, etc.) as the current message. Otherwise, you'll just see the WM_SYSCOMMAND itself.

But you can't apply the same approach in WPF, because WPF doesn't provide a GetCurrentMessage() method or its equivalent (as far as I know). The only access to window messages you get is to override the Control.WndProc() method, and by the time you get the close command, the most recent window message there will always be the SC_CLOSE.

It seems to me that the best you can do is use the WndProc() override to track incoming messages, so that you can reset a flag when non-close-command messages come in.

Then, when you get the close command and display the user prompt, you can check that flag. If it's set true, then you can ignore the prompt and just use whatever the user most recently selected. Since you're clearing the flag any time non-close-command messages come in, the first close command received will always display the prompt.


Another alternative would be pre-emptively close all the remaining windows. Here you'd still have the prompt have some kind of "apply to all other windows" option for the user, but instead of setting of just relying on the flag, you could actually close all the other windows explicitly.


Neither of these are ideal, from a user-interface perspective. The main problem is when the user tries to close just a single window. In the first approach, the user will see the "apply to all other windows" option in the prompt even though there won't be any other windows to close. The second approach is a bit more self-consistent, but adds a feature you may or may not want: the user can close all windows in the program any time they are closing just one window.

Neither of these behaviors are exactly standard Windows user interface behaviors. I.e. in trying to save the user some annoyance (and confusion, though like I said, I don't see that part being the case), you introduce what itself could be potentially confusing to the user.

Given that it involves additional work coding, and may simply exchange one annoying/confusing result for another, the best solution may be simply to not try to address the issue at all.

like image 191
Peter Duniho Avatar answered Oct 31 '22 20:10

Peter Duniho