WPF NotifyIcon
Version 1.0.8 released April 2nd 2016.
This is an implementation of a NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform. It does not just rely on the Windows Forms NotifyIcon component, but is a purely independent control which leverages several features of the WPF framework in order to display rich ToolTips, Popups, context menus, and balloon messages. It can be used directly in code or embedded in any XAML file.
Browse/fork/clone on GitHub (includes sample application)
Download library via NuGet
Features at a glance
- Custom Popups (interactive controls) on mouse clicks.
- Customized ToolTips (Vista and above) with fallback mechanism for xp/2003.
- Rich event model including attached events to trigger animations in Popups, ToolTips, and balloon messages. I just love that.
- Full support for standard Windows balloons, including custom icons.
- Custom balloons that pop up in the tray area. Go wild with styles and animations 🙂
- Support for WPF context menus.
- You can define whether to show Popups on left-, right-, double-clicks etc. The same goes for context menus.
- Simple data binding for Popups, ToolTips and custom balloons through attached properties and derived data context.
- Command support for single / double clicks on the tray icon.
Tutorial and Support
-
-
- A comprehensive tutorial that complements the attached sample application can be found on the Code Project:
-
http://www.codeproject.com/KB/WPF/wpf_notifyicon.aspx
Please post support questions to the CodeProject forum only. Thank you.
Screenshots
The screenshots below were taken from NetDrives and the sample application.
XAML Declaration Sample
The sample below shows some of the properties of the control. For a more comprehensive sample, have a look at the sample application that comes with the download.
<Window x:Class="Hardcodet.NetDrives.UI.SystemTray.Sample" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:tb="http://www.hardcodet.net/taskbar"> <tb:TaskbarIcon x:Name="myNotifyIcon" Visibility="Visible" ToolTipText="Fallback ToolTip for Windows xp" IconSource="/Images/TrayIcons/Logo.ico" ContextMenu="{StaticResource TrayMenu}" MenuActivation="LeftOrRightClick" TrayPopup="{StaticResoure TrayStatusPopup}" PopupActivation="DoubleClick" TrayToolTip="{StaticResource TrayToolTip}" /> </Window>
Thank you so much, Philipp! I’m looking forward to getting rid of the Winforms dependency.
You’re welcome – happy coding 🙂
What are the terms of use. I want it to use for free school-program, is that ok?
Fabian,
This is free software and the license (CodeProject Open License) even permits you to develop closed-source commercial software, so no worries.
Hie,
Very impressive work !
Thank’s for sharing it.
Maybe a problem : in ‘TaskBarIcon.cs’, the 2 call to ‘Popup.CreateRootPopup( )’ throws several binding expressions error in visula studio output window.
Loic
Loic,
Popup.CreateRootPopup tries to create the binding that you saw in the debug window, but this is nothing to worry about – CreateRootPopup just tries to bind to these properties in case the control you want to use for a popup should behave accordingly. For more information, use reflector to have a look at the CreateRootPopup method, and see the MSDN page of CreateRootPopup: http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.popup.createrootpopup.aspx
If the debug output annoys you, you can replace the CreateRootPopup call by: popup.Child = TrayPopup;
Edit: Version 1.0.1 no longer calls CreateRootPopup, so the debugs warning are gone.
Cheers,
Philipp
This is excellent, I was just looking for a NotifyIcon for WPF.
Thanks!
Cheers Klaus – hope it comes in handy!
hey Philip, nice work on this – very nice looking little library.
I’ve had a problem using your trayicon in my MVVM app though. It seems the DataContext is not getting set on the ContextMenu so if I bind a MenuItem’s Command property to my ViewModel the Commands are not getting executed. I’ve fixed this by modding your source code to set the DataContext property of the ContextMenu in the ShowContextMenu – not sure if this is the recommended approach but it’s working for me.
cheers
Nic
I’d say it’s the expected behavior, because the TaskbarIcon is not set as the ContextMenu’s PlacementTarget. I could either use the attached property to give you access to the TaskbarIcon or explicitely assign the DataContext. I’ll think about it and will get back to you.
Edit: Version 1.0.1 solves this issue – ContextMenu is now a first class citizen when it comes to DataBinding and also gets the TaskbarIcon’s DataContext and ParentTaskbarIcon attached dependency property (see tutorial / data binding samples.
Any plans of adding this to Codeplex? It might serve to get it more exposure and contribution. This is definitely something that should be added to the WPF toolkit. Though it probably wouldn’t be since it’s a Windows Desktop only type of control, still something that has been sorely missing when doing wpf apps.
Jeff,
I’m currently outlining a CodeProject article for this one – this should give it some more exposure. I’ll think about CodePlex – thanks for the suggestion 🙂
This is great stuff!.. thanks 🙂
Thanks Björn – glad you like the control! And stay tuned – I’m finalizing V 1.0.1 and a set of tutorials on the subject.
Oh, this is great. Much better than the standard WinForm icon. It’s no wonder that microsoft will ask you to integrate this in WPF 4 😛
Hehe, I doubt that. Cheers Fox 🙂
Hi,
Can you describe a little bit more the need of this namesapace:
xmlns:tb=”http://www.hardcodet.net/taskbar”>
You can compare a namespace with a using statement in C# – it basically tells the XAML parser where to find the declared class. For further information, have a look here:
http://msdn.microsoft.com/en-us/library/ms747086.aspx
Hi. Thanks a lot for this code. It’s great.
I made a modification to make it work with RoutedCommands. Right now if you assign a RoutedCommand to LeftClickCommand or DoubleClickCommand, the command is not invoked. This is due to the way you are invoking commands in the ‘ExecuteIfEnabled’ extension method and arguably due to a bad implementation of the RoutedCommand ‘CanExecute’ method.
To make this scenario work, you must add the following method to the ‘TaskbarIcon’ class and replace the 5 calls to ‘ExecuteIfEnabled’ by a call to this new method:
protected void ExecuteCommandIfEnabled(ICommand command, object commandParameter)
{
if (command != null)
{
RoutedCommand routedCommand = command as RoutedCommand;
if (routedCommand == null)
{
command.ExecuteIfEnabled(command);
}
else
{
if (routedCommand.CanExecute(commandParameter, this))
{
routedCommand.Execute(commandParameter, this);
}
}
}
}
Thanks again.
Rodolfo,
Thanks for the contribution. This is fixed in 1.0.3 which also provides
CommandTarget
properties for both commands.Thanks for the code! For interop scenarios (which happens to be my case, i.e. MFC app invoking managed COM object) I would add GuiDispatcher property since in these cases Application.Current will be null. That’s what I did and so far it works just fine within a MFC app.
A bit more elegant – adding GuiThreadDispatcher property and then initializing it in constructor like:
GuiThreadDispatcher = Dispatcher.CurrentDispatcher;
takes care of possibly null Application object. User is obliged to create icon on UI thread but that is nothing unusual with WPF.
It seems that it is not possible to host a textbox in a taskbar popup. It will be displayed but I can’t enter text. Pasting text from clipboard is possible though…
Has anyone experienced the same issue?
BTW thanks for sharing this knowledge and code…
Hi Philip,
Looks like an excellent control. I got it up and running pretty easy.
One question though. Do you know why my input controls (TextBox for example) do not receive focus once I place them on the popup? It appears that a TextBox does work when I add it to the WelcomeBalloon.xaml, which is a custom balloon. If I set the WelcomeBalloon to be the popup, the TextBox is unable to receive focus.
I’d like to be able to use a TextBox on the PopUp so that people are able to enter their current status which is then immediately updated, like Live Messenger. Hope you can point me in the right direction.
Thanks!
Hi,
thanks for the tutorial. but I tried it and I continued to get an error stating that i was missing a assembly reference. I did add xmlns:tb=”http://www.hardcodet.net/taskbar” in the namespace. My code looks identical to the code provided, any suggestions?
thanks,
Mike
Mike, did you add a reference to the assembly (the DLL in the “References” folder) in your project?
It’s not working in Windows 7 RTM x64, getting invalid menu handle in the CreateMessageWindow() method apart of WindowMessageSink.cs. XP works fine, don’t know about Vista. Can you fix it. Also you need to update your sample took me forever to get it to compile under VS 2010.
@seven
Seven, the project runs just fine on Win7 RC1 x64, at least under VS2008. Haven’t looked at it in VS2010 yet, but given the new VS is beta software, I don’t plan on changing the code for it so far. Of course, if the problem’s still there with .NET 4.0 RTM, I’ll provide an update asap.
Hi There
Are there any samples out there where I am ale to get VB.NET samples
Dave,
I’m afraid the sample is only available as a C# project. However – most is XAML anyway, so this shouldn’t make too much of a difference. If you want to convert the code in the sample application, you can run it through a converter, e.g. http://converter.telerik.com/
And in case you haven’t already, check out the CodeProject tutorial.
Hello Philipp,
This question was also posted on CodeProject by “headarmleg”. I am having the same problem.
Here is what “headarmleg” wrote
This is great tool, thanks for posting!
Only problem I’m having is trying to show a custom balloon containing a listbox. When I display the control it shows the listbox with all of it’s items correctly and the scroll bars work. What I can’t seem to get working is to be able to select items or handle the selection changed event. Anyone know what I’m doing wrong? Thanks in advance!
I was able to reproduce this in the FancyPopup.xaml sample by adding the following in the grid (covering the textblock in the middle)
None of the items are selectable.
Do you have any thoughts on why this is happeing, or what might make it work.
Thanks
Kevin
@Sander Schutten
Same problem here, the textbox aren’t able to take input.
Here’s a sample to reproduce :
When the textBox is displayed we can’t put text in it.
nevertheless, good job on that one !
I’m on the issue with the disabled TextBox – this can be reproduced with regular Popups as well. I’ll have time to look at it next week and hopefully come up with a workaround.
Edit: Should be fixed with 1.0.4
@Tony Juricic
Can you create a sample usage within winforms/win32 application?
Hi Philip,
Thanks for the sharing.
I found it does work well in windows XP with SP1(VS2008),However, it doesn’t work in windows XP without SP1(VS2008).
Could you please give some advice about this issue?
Daniel,
I’m afraid I don’t have a machine where SP1 isn’t present, here. SP1 was a major upgrade which I’d recommend to be present anyway. I don’t know exactly what the dependency is, but: Did you try to compile the component alone (without the sample application)?
Thanks you!
The issues with Popups and/or ListView controls should be fixed with 1.0.4. Thanks to all for reporting the bug 🙂
Myabe a bug or maybe not.
I was trying to use the OS standard popups (ShowBalloonTip) but it didn’t work. The problem was my Icon because its was 48×48, I tried a 16×16 one and it worked… (You can see the 48×48 icon in the tray but the popup didn’t work)
@Fox
I’m pretty sure this is an OS restriction. Thanks for posting the solution!
For some reason the LeftMouseButtonUp events have not been firing for the Context menu items.
I have tried in xaml and in code to hook to the event, but have not been successful.
Am I missing something?
Thank you so much Mr. Sumi.
Its realy great job.
Regards…
@mbaldini
This event never fires for context menu items – you can easily reproduce this with a regular context menu on a window.
Very nice!
One quick suggestion – your RoutedEventHelper class has special cases for UIElement and ContentElement, but the relevant methods are defined on the IInputElement interface. This would simplify the code and also cover UIElement3D.
internal static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
{
var element = target as IInputElement;
if (null != element) element.RaiseEvent(args);
}
To make it more WPFish, Icon should allow URIs like Window Icon property does, e.g.
This is allowed, thus: should be allowed too.
I find it highly illogical that such problems are also in Microsoft’s own libraries, Window element takes URI’s just fine, but MenuItem.Icon takes ImageSources, very confusing when same named properties doesn’t eat same stuff.
Thanks, great work btw!
@Ciantic
I think you are looking for the
IconSource
property. The NotifyIcon supports both 🙂@Philipp Sumi
Oh thats fantastic, (awesome fast reply), though I still think that same named property should eat same kind of stuff. (Maybe some converter could route it to IconSource?)
@Ciantic
A single property won’t do – these are different data types.
IconSource
is what you use in XAML, while you can use theIcon
property to simply assign the icon in code (e.g. if your icon is in a resource file, and that’s also the component’s internal format).Have a look at the CodeProject tutorial, it shows both scenarios.
Happy coding!
Philipp
Bug nr. 2 (Context menu is wrongly placed when used in two places)
Here is full details and patch to that also: http://users.jyu.fi/~jaotospe/wpficon_bug2.txt
@Ciantic
This is not a bug, but by design. I had to look into the change log for the reason, though:
CHG Popups and ContextMenu now store coordinates - otherwise delayed opening may happen elsewhere.
You can reproduce this by just setting the
MenuActivation
toLeftClick
. If you now left-click the NotfiyIcon and move the mouse away quickly, the context menu will open at the mouse pointer’s location, which is not the desired place. This is because there is noPlacementTarget
set for the context menu.Still: If you want to reuse the same context menu by the NotifyIcon and other elments on your window, just declare it as a resource, with
x:Shared="false"
. Like this, your NotifyIcon will have an independent menu for itself.