Combine NotifyIcon and ToolTip - c#

I have been working with NotifyIcon in order to show an icon in the taskbar.
This program has no Windows Form. I perhaps could create one and make it invisible but I was hoping to avoid it. The ToolTip functions attached to NotifyIcon are somewhat lacking, and one of the gurus here suggested I look at the ToolTip functionality. It is possible to attach ToolTip to a form. Is is possible to attach it to just the NotifyIcon? I'm trying do this:
NotifyIcon CTicon = new NotifyIcon();
ToolTip toolTip = new ToolTip();
toolTip.SetToolTip(CTicon, "Test");
And I get the error "cannot convert from 'System.Windows.Forms.NotifyIcon' to 'System.Windows.Forms.Control'. Is there a way to convert? I also tried:
toolTip.SetToolTip(CTicon.Container, "Test");
but a container is apparently not a valid control either.
I apologize for my total lack of understanding of how this may or may not work.
Thanks in advance.

A belated answer, but maybe useful for others .
NotifyIcon.Text = "ToolTipText";

Tray icons don't support square tool tips, only balloons. Kinda makes sense, the icons are usually quite close together so it would be hard to see what icon produced the tip without the "stem" on the balloon. Use the NotifyIcon.BalloonTipText property.

NotifyIcon is used for the system tray icon that you see on the bottom right hand corner of the screen, usage of ToolTip is only for controls such as textboxes, checkboxes and so on...for example, let's assume there's a TextBox instance called 'textBox1', on the form than this would work:
toolTip1.SetToolTip(textBox1, "Hello World");
Now, when you mouse-over the textbox, a tooltip is shown...

I'm not sure you can set a tooltip directly on a notify icon. It's the same thing as setting the text property on the notify icon itself. There are some limitations to the notify icon text. It's limited to 128 chars and will only stay up for a short amount of time. If you want to display more info for a longer amount of time you should look at the balloon text property of the notify icon. I highly suggest reading the MSDN page it's quite helpful.
http://msdn.microsoft.com/en-us/library/system.windows.forms.notifyicon.aspx

You shouldn't.
NotifyIcon is used to show notifications, whereas ToolTip is used to show the information about the user's current activity, it should be used "in place".
Check the user interface guidelines:
Notifications
Balloons

All the tray icons on my computer have tooltips. You need to create your NotifyIcon using the constructor that accepts a Component as an argument. It displays the NotifyIcon.Text property.
I was able to create one using the example code here:
http://msdn.microsoft.com/en-us/library/1by05f8d.aspx
using System;
using System.Drawing;
using System.Windows.Forms;
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.NotifyIcon notifyIcon1;
private System.Windows.Forms.ContextMenu contextMenu1;
private System.Windows.Forms.MenuItem menuItem1;
private System.ComponentModel.IContainer components;
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
public Form1()
{
this.components = new System.ComponentModel.Container();
this.contextMenu1 = new System.Windows.Forms.ContextMenu();
this.menuItem1 = new System.Windows.Forms.MenuItem();
// Initialize contextMenu1
this.contextMenu1.MenuItems.AddRange(
new System.Windows.Forms.MenuItem[] {this.menuItem1});
// Initialize menuItem1
this.menuItem1.Index = 0;
this.menuItem1.Text = "E&xit";
this.menuItem1.Click += new System.EventHandler(this.menuItem1_Click);
// Set up how the form should be displayed.
this.ClientSize = new System.Drawing.Size(292, 266);
this.Text = "Notify Icon Example";
// Create the NotifyIcon.
this.notifyIcon1 = new System.Windows.Forms.NotifyIcon(this.components);
// The Icon property sets the icon that will appear
// in the systray for this application.
notifyIcon1.Icon = new Icon("appicon.ico");
// The ContextMenu property sets the menu that will
// appear when the systray icon is right clicked.
notifyIcon1.ContextMenu = this.contextMenu1;
// The Text property sets the text that will be displayed,
// in a tooltip, when the mouse hovers over the systray icon.
notifyIcon1.Text = "Form1 (NotifyIcon example)";
notifyIcon1.Visible = true;
// Handle the DoubleClick event to activate the form.
notifyIcon1.DoubleClick += new System.EventHandler(this.notifyIcon1_DoubleClick);
}
protected override void Dispose( bool disposing )
{
// Clean up any components being used.
if( disposing )
if (components != null)
components.Dispose();
base.Dispose( disposing );
}
private void notifyIcon1_DoubleClick(object Sender, EventArgs e)
{
// Show the form when the user double clicks on the notify icon.
// Set the WindowState to normal if the form is minimized.
if (this.WindowState == FormWindowState.Minimized)
this.WindowState = FormWindowState.Normal;
// Activate the form.
this.Activate();
}
private void menuItem1_Click(object Sender, EventArgs e) {
// Close the form, which closes the application.
this.Close();
}
}

Related

Minimize and Hide Winform on Form Load

I have a Windows Form in a C# program with the FormBorderStyle set to FixedToolWindow.
The window doesn't have the normal control box, but the user can still minimize it from a menu. There is also a setting for the window to start in a minimized state.
When the user clicks the minimize button it called the following function:
private void minimizeWindow()
{
timer1.Enabled = false;
this.WindowState = FormWindowState.Minimized;
this.Hide();
}
The window becomes a small box in the bottom left of the screen, then disappears (from the this.hide call).
When the same function is called from within the Form_Load method (when the setting is to start minimized) it minimizes but does not disappear.
My guess is that because I am hiding the form before reaching the end of Form_Load it is being shown again when it reaches the end of the method. Is there any way to ensure the form hides when it is loaded (it is maximised again from a system tray icon)?
Edit: Included all code from form load
private void Form1_Load(object sender, EventArgs e)
{
this.Left = windowXPos;
this.Top = windowYPos;
sysTrayIcon.MouseDoubleClick += new MouseEventHandler(sysTrayIcon_MouseDoubleClick);
sysTrayIcon.BalloonTipText = "Timers Running";
this.sysTrayIcon.Icon = this.Icon;
sysTrayIcon.Visible = true;
sysTrayIcon.ShowBalloonTip(500);
Start(); //sets up timers
if (startMinimized)
{
minimizeWindow();
}
}
It might be best to change your logic slightly, and instead of showing the form at all, create an instance of it (var foo = new MyForm()) but don't call .Show() so it will never be shown until triggered from your system tray icon.

Why Won't Form Get Focus?

I have a form that is launched modally like this:
private void find_street_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
Form findForm = new FindStreet();
findForm.ShowDialog();
this.WindowState = FormWindowState.Normal;
}
The form launches correctly, and the cursor is in the first text box, whose TabIndex is set to 1.
Along with the InitializeComponent(); call, these commands are present.
public FindStreet()
{
InitializeComponent();
this.TopMost = true;
this.BringToFront();
this.Focus();
}
I have looked at and tried a number of examples. The cursor appears in the correct control, but the form's window does not have the focus. The problem is that if a user starts typing, even though the newly launched form is visible, those keystrokes are not going into the text box.
Remove the code in public FindStreet() and in load event of FindStreet add:
this.TopMost = true; //i don't know why you need this.
this.Activate();
When you minimize your main form the next one in z-order get the cursor. this.Focus() doesn't do anything. You need to Activate the dialog.
A dialog requires an owner, that cannot be a minimized window. Now accidents start to happen, starting with your WindowState assignment. Your app doesn't have a window left that can receive the focus so Windows is forced to find another one, that will be one owned by another application. Same problem happens when you close the dialog.
You can still get the intended effect, you must hide your main window after the dialog is displayed, show it again before the dialog closes. That requires a bit of hackorama:
using (var dlg = FindStreet()) {
// Show main window when dialog is closing
dlg.FormClosing += new FormClosingEventHandler((s, cea) => {
if (!cea.Cancel) this.Show();
});
// Hide main window after dialog is shown
this.BeginInvoke(new Action(() => {
this.Hide();
}));
dlg.StartPosition = FormStartPosition.Manual;
dlg.Location = this.Location;
if (dlg.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
// etc...
}
}
And remove the hacks from the FindStreet constructor. Watch out for event order if you have a FormClosing event handler in FindStreet, be sure to override OnFormClosing() instead.
If you want to set a specific control as the current active control then try this:
this.ActiveControl = myTextBox;
This will place the cursor you want as the main focus, when the form loads. So try this out:
public FindStreet()
{
InitializeComponent();
this.TopMost = true;
this.BringToFront();
this.Focus();
this.ActiveControl = myTextBox;
}
Here is the link to Focus() which should explain why your focus call was not working.

C#.NET MDI bugs when programmatically hiding and showing again a maximized child form and when maximized, child form's icon cannot be changed

Basically I am having two problems with C#.NET MDI. You can download VS2010 solution which reproduces bugs here.
1) When programmatically hiding and showing again a maximized child form, it is not maximized properly again and becomes neither maximized or in normal state.
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
...
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
}
...
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
}
When child form is maximized, then programicaly hidden and shown again, it becomes something like this (please notice the menu bar - child form's control box appears, but child form is not maximized):
At this stage, child form cannot be moved around. However, I found a workaround for that, simply by showing and hiding a dummy child form, which forces the actual child form to become properly maximized. But this makes MDI area to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Maybe there are other workarounds to overcome this bug and not to make MDI area flicker with dummy child form?
private void workaround1Button_Click(object sender, EventArgs e)
{
dummyForm.Visible = true;
dummyForm.Visible = false;
}
2) When child form is maximized, the icon of the child form is displayed on menu bar. However, if you have to change the icon while the child form is maximized, the icon on the menu bar is not being refreshed (see the image above). I found a workaround for that too, which basically hides and shows menu bar. Icon gets refreshed, but it makes everything below menu bar to flicker. Tried Invalidate, Refresh, Update methods, but they don't help. Is there any other way to make menu bar to refresh the child form's icon?
private void workaround2Button_Click(object sender, EventArgs e)
{
menuStrip.Visible = false;
menuStrip.Visible = true;
}
Also I noticed that when parent form is in normal window state mode (not maximized) and you change the width or height of the form by 1 pixel, child form becomes maximized as it should be and child form's icon on menu bar gets refreshed properly and you don't need other workaround I described above. If I change the size of the form programicaly, form flickers by 1 pixel and I cannot do that, when parent form is maximized. Is there any way how I could invoke the repaint/refresh functionality which is called when you resize a form and which makes child form become maximized properly and the icon on the menu bar refreshed?
There's a bug in the implementation of the internal MdiControlStrip class, the control that displays the icon and the min/max/restore glyphs in the parent window. I haven't characterized it as yet, the code isn't that easy. A classic side effect of the bug is that the glyphs get doubled up, you found some other side-effects. The fix is simple though, delay creating the child windows until after the constructor is completed. Like this:
public MainForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e) {
childForm = new Form();
childForm.Text = "Child Form";
childForm.MdiParent = this;
dummyForm = new Form();
dummyForm.MdiParent = this;
dummyForm.WindowState = FormWindowState.Maximized;
base.OnLoad(e);
}
Have you tired using Hide/Show instead of setting visible to true/false?
Try:
private void showButton_Click(object sender, EventArgs e)
{
childForm.Show();
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Hide();
}
How about this workaround?
private void showButton_Click(object sender, EventArgs e)
{
childForm.Visible = true;
childForm.WindowState = (FormWindowState)childForm.Tag;
}
private void hideButton_Click(object sender, EventArgs e)
{
childForm.Visible = false;
childForm.Tag = childForm.WindowState;
childForm.WindowState = FormWindowState.Normal;
}
UPDATE
I just gave you the idea how you could do. A better solution using the same idea as above would be a new base form which saves the windows state. See below. Derive your forms from FixedForm instead of Form:
public partial class FixedForm : Form
{
private FormWindowState lastWindowState;
public FixedForm()
{
InitializeComponent();
}
protected override void OnVisibleChanged(EventArgs e)
{
base.OnVisibleChanged(e);
if (Visible)
{
WindowState = lastWindowState;
}
else
{
lastWindowState = WindowState;
WindowState = FormWindowState.Normal;
}
}
}
Found a way how to come around those bugs.
First of all you need to suspend painting for a form and its children. I found a very helpful thread here, which describes how to do it.
After suspending painting, you need call UpdateBounds method of the control and increase ClientRectangle Width or Height by one and then decrease it back to the same value it was before. This invokes layout functionality which makes everything to update/repaint. Last step is to enable painting. Not very nice solution I guess, but it works.
StopDrawing();
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height + 1);
UpdateBounds(Location.X, Location.Y, Width, Height, ClientRectangle.Width, ClientRectangle.Height - 1);
StartDrawing();
I find suspending painting very helpful not only for working around those two bugs, but also in general to make GUI work more smoothly. I guess this can help to remove any kind of flickering. However, this solution requires P/Invokes, which should be avoided in general.
Why not just manually reset required icon in menuStrip items, after the creation of the window:
menuStripMain.Items[0].Image = null;

WinForms Taskbar Icon - Click Event not firing

I have created a non-form c# program that uses the NotifyIcon class.
The text "(Click to Activate)" shows up when I hover the mouse.
So I am getting some events handled.
However, The "Click" event does not fire and the Context menu doesnt show up.
public class CTNotify
{
static NotifyIcon CTicon = new NotifyIcon();
static ContextMenu contextMenu = new ContextMenu();
static void Main()
{
//Add a notify Icon
CTicon.Icon = new Icon("CTicon.ico");
CTicon.Text = "(Click to Activate)";
CTicon.Visible = true;
CTicon.Click += new System.EventHandler(CTicon_Click);
//Create a context menu for the notify icon
contextMenu.MenuItems.Add("E&xit");
//Attach context menu to icon
CTicon.ContextMenu = contextMenu;
while (true) //Infinite Loop
{
Thread.Sleep(300); //wait
}
}
private static void CTicon_Click(object sender, System.EventArgs e)
{
MessageBox.Show("Clicked!");
}
}
Take a look at the Shell_NotifyIcon() API method, the one that implements a NotifyIcon. Click through to the NOTIFYICONDATA structure. The second member of that structure is a window handle:
A handle to the window that receives
notifications associated with an icon
in the notification area
You don't have a window and can therefore not receive notifications. You must put the NotifyIcon on a Form. And use Application.Run() to get the notifications and activate the event handlers.
Keep your form hidden by pasting this code:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
Why don't you create a form application, and upon initialization just hide the form? I've never had problems with notification icon using this approach
I have the same problem, when I use the .hide() event to hide the form or the SetVisibleCore that Hans provide, the click or any mouse events will not fire.
Does someone have another solution ?
P.S. While the form is visible, everything is working fine.

How can I make a .NET Windows Forms application that only runs in the System Tray?

What do I need to do to make a Windows Forms application to be able to run in the System Tray?
Not an application that can be minimized to the tray, but an application that will be only exist in the tray, with nothing more than
an icon
a tool tip, and
a "right click" menu.
The code project article Creating a Tasktray Application gives a very simple explanation and example of creating an application that only ever exists in the System Tray.
Basically change the Application.Run(new Form1()); line in Program.cs to instead start up a class that inherits from ApplicationContext, and have the constructor for that class initialize a NotifyIcon
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MyCustomApplicationContext());
}
}
public class MyCustomApplicationContext : ApplicationContext
{
private NotifyIcon trayIcon;
public MyCustomApplicationContext ()
{
// Initialize Tray Icon
trayIcon = new NotifyIcon()
{
Icon = Resources.AppIcon,
ContextMenu = new ContextMenu(new MenuItem[] {
new MenuItem("Exit", Exit)
}),
Visible = true
};
}
void Exit(object sender, EventArgs e)
{
// Hide tray icon, otherwise it will remain shown until user mouses over it
trayIcon.Visible = false;
Application.Exit();
}
}
As mat1t says - you need to add a NotifyIcon to your application and then use something like the following code to set the tooltip and context menu:
this.notifyIcon.Text = "This is the tooltip";
this.notifyIcon.ContextMenu = new ContextMenu();
this.notifyIcon.ContextMenu.MenuItems.Add(new MenuItem("Option 1", new EventHandler(handler_method)));
This code shows the icon in the system tray only:
this.notifyIcon.Visible = true; // Shows the notify icon in the system tray
The following will be needed if you have a form (for whatever reason):
this.ShowInTaskbar = false; // Removes the application from the taskbar
Hide();
The right click to get the context menu is handled automatically, but if you want to do some action on a left click you'll need to add a Click handler:
private void notifyIcon_Click(object sender, EventArgs e)
{
var eventArgs = e as MouseEventArgs;
switch (eventArgs.Button)
{
// Left click to reactivate
case MouseButtons.Left:
// Do your stuff
break;
}
}
I've wrote a traybar app with .NET 1.1 and I didn't need a form.
First of all, set the startup object of the project as a Sub Main, defined in a module.
Then create programmatically the components: the NotifyIcon and ContextMenu.
Be sure to include a MenuItem "Quit" or similar.
Bind the ContextMenu to the NotifyIcon.
Invoke Application.Run().
In the event handler for the Quit MenuItem be sure to call set NotifyIcon.Visible = False, then Application.Exit().
Add what you need to the ContextMenu and handle properly :)
Create a new Windows Application with the wizard.
Delete Form1 from the code.
Remove the code in Program.cs starting up the Form1.
Use the NotifyIcon class to create your system tray icon (assign an icon to it).
Add a contextmenu to it.
Or react to NotifyIcon's mouseclick and differenciate between Right and Left click, setting your contextmenu and showing it for which ever button (right/left) was pressed.
Application.Run() to keep the app running with Application.Exit() to quit. Or a bool bRunning = true; while(bRunning){Application.DoEvents(); Thread.Sleep(10);}. Then set bRunning = false; to exit the app.
"System tray" application is just a regular win forms application, only difference is that it creates a icon in windows system tray area. In order to create sys.tray icon use NotifyIcon component , you can find it in Toolbox(Common controls), and modify it's properties: Icon, tool tip. Also it enables you to handle mouse click and double click messages.
And One more thing , in order to achieve look and feels or standard tray app. add followinf lines on your main form show event:
private void MainForm_Shown(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
Hide();
}
I adapted the accepted answer to .NET Core, using the recommended replacements for deprecated classes:
ContextMenu -> ContextMenuStrip
MenuItem -> ToolStripMenuItem
Program.cs
namespace TrayOnlyWinFormsDemo
{
internal static class Program
{
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
Application.Run(new MyCustomApplicationContext());
}
}
}
MyCustomApplicationContext.cs
using TrayOnlyWinFormsDemo.Properties; // Needed for Resources.AppIcon
namespace TrayOnlyWinFormsDemo
{
public class MyCustomApplicationContext : ApplicationContext
{
private NotifyIcon trayIcon;
public MyCustomApplicationContext()
{
trayIcon = new NotifyIcon()
{
Icon = Resources.AppIcon,
ContextMenuStrip = new ContextMenuStrip()
{
Items = { new ToolStripMenuItem("Exit", null, Exit) }
},
Visible = true
};
}
void Exit(object? sender, EventArgs e)
{
trayIcon.Visible = false;
Application.Exit();
}
}
}
As far as I'm aware you have to still write the application using a form, but have no controls on the form and never set it visible. Use the NotifyIcon (an MSDN sample of which can be found here) to write your application.
Here is how I did it with Visual Studio 2010, .NET 4
Create a Windows Forms Application, set 'Make single instance application' in properties
Add a ContextMenuStrip
Add some entries to the context menu strip, double click on them to get the handlers, for example, 'exit' (double click) -> handler -> me.Close()
Add a NotifyIcon, in the designer set contextMenuStrip to the one you just created, pick an icon (you can find some in the VisualStudio folder under 'common7...')
Set properties for the form in the designer: FormBorderStyle:none, ShowIcon:false, ShowInTaskbar:false, Opacity:0%, WindowState:Minimized
Add Me.Visible=false at the end of Form1_Load, this will hide the icon when
using Ctrl + Tab
Run and adjust as needed.
It is very friendly framework for Notification Area Application... it is enough to add NotificationIcon to base form and change auto-generated code to code below:
public partial class Form1 : Form
{
private bool hidden = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.ShowInTaskbar = false;
//this.WindowState = FormWindowState.Minimized;
this.Hide();
hidden = true;
}
private void notifyIcon1_Click(object sender, EventArgs e)
{
if (hidden) // this.WindowState == FormWindowState.Minimized)
{
// this.WindowState = FormWindowState.Normal;
this.Show();
hidden = false;
}
else
{
// this.WindowState = FormWindowState.Minimized;
this.Hide();
hidden = true;
}
}
}
In .Net 6 I had to work the guts of my class like this:
private NotifyIcon trayIcon;
private ContextMenuStrip contextMenu1;
private ToolStripMenuItem menuItem1;
public MyCustomApplicationContext()
{
contextMenu1 = new System.Windows.Forms.ContextMenuStrip();
menuItem1 = new System.Windows.Forms.ToolStripMenuItem();
this.menuItem1.Text = "E&xit";
this.menuItem1.Click += new System.EventHandler(Exit);
this.contextMenu1.Items.AddRange(
new System.Windows.Forms.ToolStripMenuItem[] {this.menuItem1 });
trayIcon = new NotifyIcon(){Icon = Resources.AppIcon, ContextMenuStrip = this.contextMenu1, Visible = true };
}
notifyIcon1->ContextMenu = gcnew
System::Windows::Forms::ContextMenu();
System::Windows::Forms::MenuItem^ nIItem = gcnew
System::Windows::Forms::MenuItem("Open");
nIItem->Click += gcnew System::EventHandler(this, &your_class::Open_NotifyIcon);
notifyIcon1->ContextMenu->MenuItems->Add(nIItem);
You can create the form, modify it then pass it to the Application.Run as a parameter. :
internal static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
var form = new Form1();
form.Hide();
form.Opacity = 0;
form.ShowInTaskbar = false;
Application.Run(form);
}
}
Add your NotifyIcon and ContextMenu (if needed) to your form at design time as a regular app. Make sure your Notifyicon is Visible and has an icon associated. This will also let you work with a form that you may need later for any reason
Simply add
this.WindowState = FormWindowState.Minimized;
this.ShowInTaskbar = false;
to your form object.
You will see only an icon at system tray.

Categories