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.
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.
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.
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.
Surprisingly one can show more than one dialog at a time by putting the ShowDialog() call on the Dispatcher:
uiDispatcher.BeginInvoke(new Func<bool?>(myWindow.ShowDialog));
How come this works and still the UI remains running responding to user interaction once the dialog is shown (I would have thought not since ShowDialog() blocks the thread it is on which has to be the UI thread), one can even go on showing new dialogs:
Window myWindow;
for(int i = 0; i < 5; i ++)
{
myWindow = new Window();
uiDispatcher.BeginInvoke(new Func<bool?>(myWindow.ShowDialog));
}
And the UI is still responsive.
Is there something I should beware of relying on this behaviour? (I want to show one dialog on top of another when some background thread wants to - this works - the only unwanted behaviour seems to be when switching apps sometimes WPF does not know which dialog should be on top - but still allows you to bring one of the dialogs to the front by clicking on it which is unusual for a dialog as clicking outside a dialog is usually not allowed).
UPDATE: One issue I have come across is if you hide one of your dialogs the user can interact with all other Windows again! (not just the other dialogs). See: WPF Dialog not modal?
Showing a dialog does not block the UI thread -- otherwise you won't be able to interact with the dialog.
It merely marks the fact that there is a modal dialog outstanding, and that it should disable inputs to all other non-dialog windows.
If you shuff a ShowDialog call into the dispatcher, the dispatcher will allow an additional dialog to be created because you are not doing something which is prohibited when a modal dialog is outstanding -- which is to input into other non-dialog windows.
Your new dialog is fully functional, because it is a dialog, and you are not trying to input into non-dialog windows.
Switching applications should bring any modal dialog out to the front, but since you have more than one modal dialogs, the system will get confused as to which one should be top-most. I'd suggest you trap the activation event and just manually bring the necessary dialog top-most.
In the Program.cs file of the .Net CF 3.5 WinForms program I've written, I launch the app by instantiating a new instance of Form1.
Application.Run(new Form1());
When I want to close/exit the application, I override the Form1 FormClosed event so that I can ensure exiting the application.
// In Form1 code-behind
private void OnFormClosed(object sender, EventArgs e)
{
Application.Exit(); // Doesn't kill process
}
When this code runs, I want the app to disappear from the screen (close) and I want the process it was running as to die. The app closes (disappears), but unfortunately, the process (we'll call it app.exe) is still running indefinitely. When I start the app again and close it, it spins up another app.exe process, etc. So the process is never dying and more are being created eating memory.
How can I ensure this process is being killed when I close/exit the app? Thanks.
First, you should not have to overide OnFormClosed to get the behavior you're after. Just closing the Form passed in to Application.Run will cause the app's message pump to exit and should cause the process to end. For Windows Mobile you should set the ShowMinimize property of the Form to false to prevent it from just being minimized - you should have a (OK) in the upper right, not an (X).
If the process does not exit when this Form closes, then the culprit 99.99% of the time is that you have a worker thread that is still running preventing the process from closing. Make sure all of your Threads have IsBackground set to true (for CF 3.5) and as a precaution, all of your threads should also have some form of exit notification or flag. Don't rely of the process terminating to tear them down for you.
Your problem is that you have Form.MinimizeBox = true. Change it to false and the form will be closed when ok is clicked instead of minimized when x is clicked.
There are more things to consider in your question:
I override the Form1 FormClosed event
There is no FormClosed event for forms of type System.Windows.Forms.Form, only Closing and Closed.
You don't override an event. You override a virtual function from a base class or interface.