In my WPF Main Window I handle the OnClosing event - protected override void OnClosing(CancelEventArgs e). This event is also fired when Windows is shutting down, and tries to close the programs opened.
But, when Windows is shutting down, I would like to have a different logic than I would have if the user had clicked on the X button on the top right. Is there a way to distinguish if the window close was initiated by the user and not by the system?
You can use the Application.SessionEnding event to trap shutdown/logoff messages, and put your different logic in there.
Related
For cross-platform parity reasons, my GetOpenFileName() specifies no owner and I explicitly disable all toplevel windows myself. The problem is re-enabling. In order to re-enable these windows correctly, I need to re-enable them before the dialog closes.
In the case of the user choosing a file, this is no issue: I just check for CDN_FILEOK in the hook procedure. No issues, no messed-up focus.
How can I do the same, but for cancelling the dialog box?
I have tried WM_DESTROY in the hook procedure, but that runs after the dialog box has been hidden (too late). I have tried WM_COMMAND, but that doesn't seem to cover all cases. I'm not sure what other options I have.
I need to target Windows XP and newer for now; that also means no Common Item Dialogs. Thanks!
Alternative: if there was a way to do a callback-based GetOpenFileName() that returned control to my message loop, like on Mac OS X with beginSheetModalForWindow:, I could be able to specify a parent window and avoid this hack.
There is no CDN notification when the dialog is canceled. If the user presses the Cancel button, you could try intercepting the BN_CLICKED notification that it sends to the dialog, or even subclass the button itself. But if the user cancels the dialog through other means (clicking the red X, pressing ESC, etc), you will likely have to catch the WM_CLOSE message instead.
I have a WPF window myWindow, which I open using myWindow.ShowDialog() ?? true and listen to the DialogResult (DialogResult = true) to execute some code.
When I set it to either true or false, the window is disposed, is there a way I can prevent this window from closing while also getting the DialogResult? Also, is there a another way I can approach this problem?
What do you want to happen? For example:
You might want a modal dialog (so users can't interact with the rest of the UI while it is visible) but you want code to run in the main program in response to some user action in the dialog. In this case, add events to your dialog that the main program can respond to.
Or you might actually want a modeless dialog, which lets users interact with the rest of the program without completing the dialog. In this case, don't use ShowWindow, just show an owned window.
I'm looking for a "best practice" (if there is even a best) for cleanly shutting an WPF application down that uses MEF and PRISM4. Ultimately, I'm looking for some sort of "Close Service" would manage all of event/commanding from the Shell to any viewmodel (or other subscribers) that want to verify it's OK to close the application. Is the event aggregator the cleanest way? Other opinions/options?
Ideally, I'd have a button on my ToolbarView in my ToolbarRegion (1 of 2 regions in my Shell). This button would invoke a command on my ToolbarViewModel (referencing a command on my ToolbarControler) which in turn would do 2 things (I think?)...First, notify all subscribers that it's closing time and allow any of them to cancel the close and...secondly, if none cancel, somehow notify the shell to close. My app's shutdown mode is set to "ShutdownMode.OnMainWindowClose" so if the Shell closes, I should be all set.
Can someone help me out with this?
I'm developping a large application using the same stuff: MEF and PrismV4
I handle shutdown it a bit differently:
in the Shell, there is a "Tools" Region, shutdown for that is handled right in the Shell, on the close event.
Then for everything injected in the other region, which is a tabcontrol, I cast the content as IDisposable, and close every tab one by one. (Actually, it's not a tabcontrol, it's an avalondock component, but it's the same thing really).
Of course, you'll have to implement IDisposable on every class that has references etc to dispose, but it's hard to think of a "clean way of shutting down" without meantioning that interface right? =)
Now, about the EventAggregator: you may very well run into trouble, because there is no coupling: you can fire a weak event through it, but you can't wait for objects to do their work after that.
And then, you couldn't make a mechanism to cancel the shutdown.
In case you want your various views to be able to cancel the shutdown, i suggest you create an interface with a single method in it:
public interface IShutdownAware
{
bool CanShutdown();
}
Then right before you call dispose, call CanShutdown(); if they all return true, proceed with disposing, otherwise, cancel the shutdown process.
I mean exit to system tray, not minimize to system tray, ie when you click on the "red cross" in the top right corner on a Windows form, instead of application closing, it runs in the system tray instead.
You can hook to Form Closing event and cancel the closing event and hide the form
sample code
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
this.Hide();
}
Handle the FormClosing event, block the Close (e.Cancel = true) and instead minimize to the system tray as you would if you were, well, minimizing to the system tray.
You will, of course, have to have a condition under which closing the form doesn't minimize to the system tray. For example, tracking the state and if the form is already minimized then allowing the form to actually close.
It is not possible to 'exit' to the system tray, a process with a message queue must be running to allow an icon to appear in the tray and function correctly (e.g. not disappear when you hover over it)
The way adobe and others handle this is to have a separate application that just does the system tray icon, when you click it and your application isn't running it starts it, if the application is already running, it brings it to the foreground.
I found some of my winform application controls, such as DataGridView and ToolStrips, are referred to by UserPreferenceChangedEventHandlers. I have no idea what setting of the controls will generate such references and why such references keep my control alive in memory. How can I remove such references from that event? Thanks.
It is the delegate type for the SystemEvents.UserPreferenceChanged event. This event fires when Windows broadcasts the WM_SETTINGCHANGE message. Which typically happens when the user uses a control panel applet and changes a system setting.
Several controls register an event handler for this event, DataGridView, DateTimePicker, MonthCalendar, ProgressBar, PropertyGrid, RichTextBox, ToolStrip, NumericUpDown. They typically are interested in font or cue changes and anything that would affect the layout.
SystemEvents.UserPreferenceChanged is a static event. Registering a handler and forgetting to unregister it causes a memory leak, it prevents the control from being garbage collected. The listed controls ensure this doesn't happen, they unregister the event handler in either the OnHandleDestroyed() or the Dispose() method.
You'll get in trouble when neither of those two methods run. That will happen when you remove the control from the container's Controls collection and forget to Dispose() it. While forgetting to call Dispose() is not normally a problem, it is a hard requirement for controls. It is easy to forget too, controls are normally automatically disposed by the Form. But that only happens for controls in the Controls collection.
Also be sure to call Dispose() on forms that you display with the ShowDialog() method, after you obtained the dialog results. The using statement is the best way to handle that.
One more excruciating detail is important about the UserPreferenceChanged event, it is often the one that deadlocks your app when you create controls on a worker thread. Typically when the workstation is locked (press Win+L). Which cannot come to a good end when you use the controls I listed, the SystemEvents class tries to raise the event on the UI thread but of course cannot do this correctly when more than one thread has created them.
Also the kind of bug that can have a lasting effect, a splash screen for example can get the SystemEvents class to guess wrong about which thread is your UI thread. After which it then permanently raises the event on the wrong thread. Very ugly to diagnose, the deadlock is well hidden.