Remove Notification icon on WPF application on process exit - c#

There should be a pretty straightforward answer to this question but I can´t seem to find a solution. I have seen similar questions on SO (like NotifyIcon remains in Tray even after application closing but disappears on Mouse Hover) but they don´t cover my case.
I have a WPF application with a Notification Icon that is set up inside the MainWindow method:
InitializeComponent();
myIcon = new System.Windows.Forms.NotifyIcon();
myIcon.Icon = someFancyIcon;
myIcon.Visible = true;
On the xaml I have defined the Window attribute Closing="Window_Closing" so that when the window is closed it calls:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Log.Info("Closing application");
myIcon.Icon = null;
Environment.Exit(0);
}
If I ran the application and close it in the normal way, Window_Closing is called and the notification icon disappears as expected (and info is output to the log).
Problem is: this application is monitored by another process (out of my control), and that other process sometimes kills the WPF application process so that Window_Closing is never called and my application notification icon keeps on lingering on the notification area until you hover your mouse over it. Since the monitoring process can restart my application and close it again several times, the notification area is soon filled with copies of the notification icon.
How can I remove the notification icon so that even if my application is finished in some abnormal way the icon disappears?

In common case, you can't do that due how Windows Tray is designed. All the tray icons are driven by their apps: they're created by and removed by the corresponding app who owns that icon(s).
If the app is terminated abnormally the tray has no clue about that. The only case is to move mouse pointer over the orphaned icon and then it will be removed from tray as no corresponding app found alive.
What can we do then? Do not kill the app. Instead, send it a message causing it to close (so, all handlers would be called then and all resources are to be freed, including tray icons as well).

Related

How to avoid WPF Application not Responding when logging off

When trying to press the standard Windows 7 logoff button while my WPF app is running, I get "This program is preventing Windows from logging off". I would like to force it to close without having to press "Force log off".
Similarly, pressing "End Task" in the (applications) Task Manager causes it to become non-responsive rather than just close the program.
I have tried adding this to Window_Closing, but this doesn't seem to do it:
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Environment.Exit(0);
}
I'm new to WPF, but it seems to me that the window is not closing properly. How can I prevent the "program is preventing Windows from logging off" when executing the Windows logoff, or "Program is not responding" when killing it from task manager?
This should only be an issue if your application is not responding to the close events sent from Windows.
This will typically happen if you are executing code on the UI thread, which prevents it from responding to messages. As such, putting something in the closing events and similar will have no effect, as they won't be able to process until after your "work" finishes.
The proper way to handle this is to move your work onto background threads. This keeps the application responsive, which allows it to respond to the request from Windows to Close.

Handle the close event via task bar

I am developing a WPF application. I usually close applications via task bar. When we put the mouse on task bar, it will show a preview of the application. I will press the center mouse button on that preview, so the application will close.
This scenario not working in WPF applications. It will send the application to background (GUI will exit, but application still run on background). The only option I have is to handle the OnClosing() event. Is there any other method?
I had came Across Same issue When I tried to do the same thing(closing of application) when i was on a window which is not my Mainwindow(or Startup URI) object.So Its my advice that please handle the on closing event of your secondary window(other than Mainwindow) and tried to shutdown or exit your application by below code
private void DataWindow_Closing(object sender, CancelEventArgs e)
{
Application.Current.Shutdown();
// Environment.Exit();
}
Wpf automatically Shut downs application when you are on Mainwindow and tried to exit the application.

Process does not kill on form close

I have just built version one of my testing application using Windows Forms. I have noticed that when running the application, it runs completely fine no hitches, exactly like the debug view. When it comes to closing the application I have noticed that the actual executable/process name hangs within Task manager and does not correctly close.
Upon further inspection I have noticed that when calling another form without hiding the previous form, a new process is spawned (kinda expected). When closing the new form (containing a few text boxes, labels and a DataGridView) the newly spawned process does not kill it's self, but remains. Then closing the main window the window disappears from the taskbar/view, but still, the processes remain active using 8,268k - 8,308k Memory
private void ClientSearch_Click(object sender, EventArgs e)
{
ClientSearch Clientsearch = new ClientSearch();
Clientsearch.Show();
}
Standard explanations for this behavior:
Hiding your main window when you display another window and forgetting to unhide it. There is no visible window anymore, nor can the user do anything to unhide it, but your app keeps motoring of course.
Starting a thread and not making sure that it is terminated when the main window closes. Setting the thread's IsBackground property to true is a workaround for that.
Calling Application.DoEvents() in your code. A very dangerous method that permits you to close the user interface but doesn't stop the loop in which it was called so the main thread of your app does not exit either.
This kind of problem is readily visible as well when you debug your app. You might have gotten in the habit of using the red rectangle on the toolbar (aka Debug + Stop Debugging) to force the debugger to quit. The Debug + Windows + Threads debugger window can provide insight into the cause of the last two bullets. Or you can use Tools + Attach to Process to attach the debugger to a zombie process.
Call
Application.Exit();
on form close/closing.
Your applications should only be creating one process per run. A new form should not be creating a new process.

Focus Windows Explorer From C# App In Task Bar

Our company has application that runs as a task bar icon - there is no UI besides the task bar icon.
Certain events cause the task bar to launch a explorer.exe to show a directory. User interaction does not cause this, so our application does not have focus.
I am able to show the directory in windows explorer using code like this:
Process.Start("explorer.exe", "c:\somedirectory");
The problem is, the folder launches in the background and I can't seem to give it focus.
Part of the problem is that the explorer.exe process exits immediately, launching the explorer.exe process separately. I am able to find the launched window using Process.processes() and looking at the window title and start time of the process.
Once I finally get a handle on the process (and wait for it to open), I'm trying to focus it. Here's what I've tried:
//trying to bring the application to the front
form.TopMost = true;
form.Activate();
form.BringToFront();
form.Focus();
Process process = ...;
ShowWindow(process.Handle, WindowShowStyle.ShowNormal);
SetForegroundWindow(process.Handle);
SwitchToThisWindow(process.Handle, true);
ShowWindow(process.MainWindowHandle, WindowShowStyle.ShowNormal);
SetForegroundWindow(process.MainWindowHandle);
SwitchToThisWindow(process.MainWindowHandle, true);
This makes the window blink in the task bar, but it still isn't focused.
How can I get the window to come to the front of the screen?
You could use the Shell.Application scripting interface to ask Explorer to create and show a new window. I believe this is also possible using a typed interface, but the exact one escapes me at the moment.
var shellApplication = Type.GetTypeFromProgID("Shell.Application");
dynamic shell = Activator.CreateInstance(shellApplication);
shell.Open(#"C:\drop\");
This seems open the window with focus (Tested on Win 8.1 using a timer which opens after 30 seconds, then navigating around in a focused web browser until the timer fires).
To focus explorer.exe, the application itself needed focus. WinForms intentionally makes this difficult since it could be abused.
Here's how you can steal focus in WinForms. Keep in mind that it may have bad consequences.
Once your application has focus, you can focus another process:
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
SetForegroundWindow(otherProcess.MainWindowHandle);
Here's how I found the explorer process. Like I said, the explorer.exe seems to launch another process and close, so the best option seemed to be to find the most recently launched explorer.exe process:
public static Process GetExplorerProcess()
{
var all = Process.GetProcessesByName("explorer");
Process process = null;
foreach (var p in all)
if (process == null || p.StartTime > process.StartTime)
process = p;
return process;
}
Another option that wouldn't require stealing focus is to show a message from your tray icon. Then you can setup a click handler to open/focus the folder. The application would naturally have focus from the click.
trayIcon.ShowBalloonTip(3000, "", msg, ToolTipIcon.Info);
This falls more in line with "don't annoy the user" but in my case the user is far more annoyed at having to click the bubble.
Update
Finding the explorer process requires admin privileges for your app. I've found that if you focus your own application first, then launch the folder, then the folder is automatically focused. In other words, there is no need to search through the current processes and call SetForegroundWindow.

My WPF app still running if I open another Window

I'm writting an WPF application using the mvvm toolkint.
In the main windows I have a command in a button that open another window using:
catView.ShowDialog();
Well, I close that window (using a close button or the X) and when I close the main window, the app is still running and I have to kill it.
If I don't open the second window, the app shutdown normally.
Why if I open another window I can't close the app normally?
I have this in the close button of the second window:
this.DialogResult = true;
this.Close();
On the other hand, I start the app in this way (mvvm toolkit way):
Views.MainView view = new Views.MainView();
view.DataContext = new ViewModels.MainViewModel();
view.Show();
Thank you very much.
The problem is probably unrelated to opening and closing the window but is somthing inside that window.
This usually happens when you have another thread still running when you close the application, check for anything that might be creating a new thread inside the window's code (including System.Threading.Thread, ThreadPool, BackgroundWorker and 3rd party components), make sure all background threads shut down before closing the application (or if you can't shut them down at least mark them as background threads).
Also look for anything that can open another (invisible) window, it's common to use window messages to an invisible window as an inter-process communication mechanism, again look for 3rd party code that might be doing that.
Nir is correct, a thread is probably still running in your other window.
You can fix this by terminating the application's thread dispatcher when the window closes.
public Window1()
{
InitializeComponent();
// This line should fix it:
this.Closed += (sender, e) => this.Dispatcher.InvokeShutdown();
}
I'm happy to be corrected if this is not the right way to do things. Worked well for me though.
PS.
If your other window is designed to run in a different thread, then read this by Eugene Prystupa:
running-wpf-application-with-multiple-ui-threads
I don't know if this is causing your issue or not, but you don't need the call to Close() in your second window. Setting the DialogResult automatically closes the window.

Categories

Resources