System tray icon with c# Console Application won't show menu - c#

I've got a small C# (.NET 4.0) Console Application that I'd like the user to be able to interact by showing a menu when they right-click the System Tray icon. I can add an icon to the Tray with no problems, but I just cannot get the menu to appear. I'm using the following code:
NotifyIcon trayIcon = new NotifyIcon();
trayIcon.Text = "TestApp";
trayIcon.Icon = new Icon(SystemIcons.Application, 40, 40);
ContextMenu trayMenu = new ContextMenu();
trayMenu.MenuItems.Add("Blah", item1_Click);
trayMenu.MenuItems.Add("Blah2", item1_Click);
trayMenu.MenuItems.Add("Blah3", item1_Click);
trayIcon.ContextMenu = trayMenu;
trayIcon.Visible = true;
... which puts the icon in the tray. However, right-clicking the icon does nothing. I've tried various permutations of MenuItems.Add, but nothing will make the menu appear. I'm sure I'm missing something simple - any ideas what?

Try adding this after you create the icon:
Application.Run()
Note that this method will not return, so you can't do anything after calling it. This means that you'll have to do all your other work in a separate thread.
What happens is that the OS sends your application a message telling it that the tray icon has been right-clicked, but the tray icon code never sees it (because these messages are processed by Application.Run) and so can't respond by opening the menu.

Concerning Application.Run(), this is an alternative to placing all the other code in another thread would be to create the NotifyIcon, menu, events, etc on a thread other than the main thread.
This should include Application.Run() as this allows the standard application message loop to work on the current thread. Then since the events were created on the same thread, the Application.Exit() can be used to close out the notification messaging but still allow the main thread to continue. Here's a small example for a console app...
class Program
{
public static ContextMenu menu;
public static MenuItem mnuExit;
public static NotifyIcon notificationIcon;
static void Main(string[] args)
{
Thread notifyThread = new Thread(
delegate()
{
menu = new ContextMenu();
mnuExit = new MenuItem("Exit");
menu.MenuItems.Add(0, mnuExit);
notificationIcon = new NotifyIcon()
{
Icon = Properties.Resources.Services,
ContextMenu = menu,
Text = "Main"
};
mnuExit.Click += new EventHandler(mnuExit_Click);
notificationIcon.Visible = true;
Application.Run();
}
);
notifyThread.Start();
Console.ReadLine();
}
static void mnuExit_Click(object sender, EventArgs e)
{
notificationIcon.Dispose();
Application.Exit();
}
}

Here is the solution:
You have to use Application.Run() because events of gui in console mode not working.
But you can use this solution:
var task = System.Threading.Tasks.Task.Factory.StartNew(() => ShowTrayIcon());
void ShowTrayIcon()
{
some code with tray icon ...
}
This will start your setup of try icon in new thread ...

Did you add the event-handler for tray Icon mouse click?
trayIcon .MouseDown += new MouseEventHandler(trayIcon_MouseDown);
create context menu and do as following inside the trayIcon_MouseDown function
private void trayIcon_MouseDown (object sender,MouseEventArgs e)
{
//add you menu items to context menu
contextMenu.Items.Add(item);
contextMenu.IsOpen = true;
}
Try this. Think this will help you.

Related

New dialogs cause window to disappear in WPF application

I'm running WPF application which can show windows and dialogs on top of the main screen of the application (.NET Framefork 4.7.2)
I use IWindowManager interface to call ShowWindow and ShowDialog.
When I want to show some window
Execute.OnUIThread(ShowPostProcessingLoadingMsg);
private void ShowPostProcessingLoadingMsg()
{
Logger.Info("PostProcessingToolViewModel: ShowPostProcessingLoadingMsg()");
if (_processingProgressMsg != null)
{
Logger.Warn("PostProcessingToolViewModel: ShowPostProcessingLoadingMsg() Loading msg was actibe already, closing it and creating a new one.");
_processingProgressMsg.TryClose();
}
_processingProgressMsg = new LoadingMessageViewModel()
{
ShowProgressRing = Visibility.Hidden,
ShowProgressBar = Visibility.Visible,
LoadingVisualState = LoadingVisualState.Mini
};
_progress = _processingProgressMsg.Progress;
_progress?.Report(0);
_updateProgressText = _processingProgressMsg.SetMessage;
_WindowManager?.ShowWindow(_processingProgressMsg);
}
And during it I show a dialog on other thread -
private void ShowPopupInDesktop(BatteryViewModel batteryPopupViewModel)
{
_logger.Info("BatteryViewModel::ShowPopupInDesktop: Going to show battery dialog");
_isPopupOpen = true;
SetPopupPosition(batteryPopupViewModel);
_windowManager.ShowDialog(batteryPopupViewModel, BatteryPopupViewContextName);
}
Then the window which I showed disappears.
I don't know how to keep the window opened and why does the dialog make it disappear.

Check if window is minimized in UWP

I am developing a UWP application for Windows 10. I want to show a message dialog box when user reduces the size of the window. As of now, I have tried to implement the feature using this link. My purpose is being fulfilled here except the message dialog appears when user either minimizes the window or changes its size. I have also attached the code snippet below. Thank you.
private async void CoreWindow_SizeChanged(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.WindowSizeChangedEventArgs args)
{
var appView = ApplicationView.GetForCurrentView();
MessageDialog messageDialog = new MessageDialog("");
if (!appView.IsFullScreen)
{
if (!msgboxshown)
{
messageDialog = new MessageDialog("To run the application smoothly, please maximize the window.");
msgboxshown = true;
await messageDialog.ShowAsync();
msgboxshown = false;
}
}
args.Handled = true;
}
My purpose is being fulfilled here except the message dialog appears when user either minimizes the window or changes its size.
When app minimizes, it will invoke EnteredBackground event, you could detect it and show your message dialog.
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.EnteredBackground += App_EnteredBackground;
}
private async void App_EnteredBackground(object sender, EnteredBackgroundEventArgs e)
{
var messageDialog = new MessageDialog("To run the application smoothly, please maximize the window.");
await messageDialog.ShowAsync();
}
Update
As #Raymond Chen said, it looks os bug. So please use the above methods with caution.

.NET NotifyIcon randomly disappearing

I have a WPF application that consists of a long running main window. In the MainWindow constructor I define a Notify icon:
private System.Windows.Forms.NotifyIcon notifyIcon;
public MainWindow()
{
InitializeComponent();
System.Windows.Forms.ContextMenu notifyMenu = new System.Windows.Forms.ContextMenu();
System.Windows.Forms.MenuItem notifyMenuItem = new System.Windows.Forms.MenuItem();
notifyMenuItem.Text = "Exit MainWindow";
notifyMenuItem.Click += new EventHandler(notifyMenuItem_Click);
notifyMenu.MenuItems.Add(notifyMenuItem);
notifyIcon = new System.Windows.Forms.NotifyIcon();
notifyIcon.BalloonTipText = "MainWindow has been minimized. Click the tray icon to show.";
notifyIcon.BalloonTipTitle = "MainWindow";
notifyIcon.Text = "MainWindow";
notifyIcon.Icon = new System.Drawing.Icon("some.ico");
notifyIcon.Visible = true;
notifyIcon.Click += new EventHandler(notifyIcon_Click);
notifyIcon.ContextMenu = notifyMenu;
}
This is all good and well, except that sometimes the NotifyIcon simply disappears from the tray. Absolutely nowhere in the code is notifyIcon.Visible = false; set as the NotifyIcon should also be visible. My application (by requirement) does not show up in the taskbar and uses a single instance manager (if another instance starts up, the newer instance is required to abort immediately). So this leads to a situation where the application was minimized to the tray, the NotifyIcon disappears and the user things the application is not running (it is) and they cannot start a new one (single instance mechanism).
I've seen some SO posts on this matter but they seem to blame the NotifyIcon being instantiated somewhere other than the main windows, which does not apply to my case. Are there other reasons for flaky NotifyIcon behavior, as well as remedies?

How to move wpf application into minimize tray at Window Start-up C#?

I have created setup of my application using Windows Installer.
Now I want to Start application at Windows Start-Up and move it system minimize tray as i don't want to display GUI(View) at Windows Start-Up.
I have searched in Google and i found to use Registry key But that is not enough for me as i also want to move to system minimize tray and application run.
My purpose to do it is, user do not feels annoying when application starts every time when he/she starts system.
Can anyone have answer?
Thanks..
In your application, add an event handler for the FrameworkElement.Loaded event. In that handler, add the following code:
WindowState = WindowState.Minimized;
This will minimise the application when it starts.
To start the application when the computer starts, you'll need to add your program into Windows Scheduler and set it to run at startup. You can find out more on the Schedule a task page at MSDN.
You also have to set this property to remove it from the taskbar
ShowInTaskbar= false;
Maybe this answer is late, but I still want to write it down to help those who haven't found solutions yet.
Firstly you need to add a function to minimize your app to tray when it autostarts as system startup.
In your App.xaml file, change the original StartupUri=... to Startup="App_Startup" as below. App_Startup is your function name and can be changed.
<Application x:Class="Yours.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Startup="App_Startup">
In your App.xaml.cs file. Add the function below:
public partial class App : Application
{
private void App_Startup(object sender, StartupEventArgs e)
{
// Process command line args
var isAutoStart = false;
for (int i = 0; i != e.Args.Length; ++i)
{
if (e.Args[i] == "/AutoStart")
{
isAutoStart = true;
}
}
// Create main application window, starting minimized if specified
MainWindow mainWindow = new MainWindow();
if (isAutoStart)
{
mainWindow.WindowState = WindowState.Minimized;
}
mainWindow.OnAutoStart();
}
}
In your MainWindow.xaml.cs, add a function as below:
public void OnAutoStart()
{
if (WindowState == WindowState.Minimized)
{
//Must have this line to prevent the window start locatioon not being in center.
WindowState = WindowState.Normal;
Hide();
//Show your tray icon code below
}
else
{
Show();
}
}
Then you should set you app utostart as system start.
Now if you have a switch to decide whether you app to autostart as system start, you can just add the function below as your switch status changed event function.
private void SwitchAutoStart_OnToggled(object sender, RoutedEventArgs e)
{
const string path = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Run";
var key = Registry.CurrentUser.OpenSubKey(path, true);
if (key == null) return;
if (SwitchAutoStart.IsOn)
{
key.SetValue("Your app name", System.Reflection.Assembly.GetExecutingAssembly().Location + " /AutoStart");
}
else
{
key.DeleteValue("Your app name", false);
}
}
If you want to automatically start the application for all users on Windows startup, just replace the forth line with
RegistryKey key = Registry.LocalMachine.OpenSubKey(path, true);
^_^

How to fix message boxes appearing behind splash screen?

My WinForms app's main window is slow to load (up to 20 seconds, depending on arguments), so it needs a splash screen.
The main window constructor is slow because it exercises thousands of lines of code (some of it beyond my influence). Sometimes this code pops up message boxes.
I've tried two splash screen designs, they each have problems. Any better ideas?
Splash screen with BackgroundWorker
static void Main(string[] args)
{
var splash = !args.Contains("--no-splash");
if (splash)
{
var bw = new BackgroundWorker();
bw.DoWork += (sender, eventArgs) => ShowSplash();
bw.RunWorkerAsync();
}
var app = new FormMain(args); // slow. sometimes opens blocking message boxes.
Application.Run(app);
}
private static void ShowSplash()
{
using (var splash = new FormSplash())
{
splash.Show();
splash.Refresh();
Thread.Sleep(TimeSpan.FromSeconds(2));
}
}
Problems:
Splash screen sometimes expires before main window open (user thinks app has crashed)
Main window sometimes minimises when splash closes.
Splash screen with WindowsFormsApplicationBase
sealed class App : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new FormSplash();
}
protected override void OnCreateMainForm()
{
// slow. sometimes opens blocking message boxes.
this.MainForm = new FormMain(this.CommandLineArgs);
}
}
Problems:
Any MessageBoxes opened appear behind splash screen, silently. User won't notice it and thinks app is stuck.
If splash screen is 'always on top', the message box is inaccessible and unclickable.
I agree with Hans Passant in that the code needs to be re-evaluated as the design seems incorrect.
As for the problem at hand, you should be able to resolve this by creating your own instance of a messageBox.
I tested using this code;
public DialogResult TopMostMessageBox(string message, string title, MessageBoxButtons button, MessageBoxIcon icon)
{
return DisplayMessageBox(message, title, button, icon);
}
public DialogResult DisplayMessageBox(string message, string title, MessageBoxButtons buttons, MessageBoxIcon icon)
{
DialogResult result;
using (var topmostForm = new Form {Size = new System.Drawing.Size(1, 1), StartPosition = FormStartPosition.Manual})
{
var rect = SystemInformation.VirtualScreen;
topmostForm.Location = new System.Drawing.Point(rect.Bottom + 10, rect.Right + 10);
topmostForm.Show();
topmostForm.Focus();
topmostForm.BringToFront();
topmostForm.TopMost = true;
result = MessageBox.Show(topmostForm, message, title, buttons, icon);
topmostForm.Dispose();
}
//You might not need all these properties...
return result;
}
//Usage
TopMostMessageBox("Message","Title" MessageBoxButtons.YesNo, MessageBoxIcon.Question)
Again, I need to stress that I agree that the original code needs to be re-factored and am only providing a possible solution to the question.
Hope this helps?
You can implement our own message box and use TopMost property, with TopMost you will get message in-front of splash screen loader.
More about topmost: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.topmost.aspx
In the end, moved the slow code from the constructor to a handler for the OnShown event.
Used WindowsFormsApplicationBase for splash screen as Hans Passant suggested, carefully checked the remaining constructor code to make sure it'll never open an message boxes.

Categories

Resources