Click here to Skip to main content
11,648,094 members (65,186 online)
Click here to Skip to main content

WPF NotifyIcon

, 23 Nov 2013 CPOL 673.4K 26.3K 590
Rate this:
Please Sign up or sign in to vote.
A NotifyIcon for WPF that leverages several features of the platform.

...or clone/fork it from Bitbucket: https://bitbucket.org/hardcodet/notifyicon-wpf/

Introduction   

This is an alternative implementation of a NotifyIcon (system tray icon) for the WPF platform. It does not just rely on the corresponding WinForms 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.  

wpf_notifyicon/ToolTip.png

Background

During the development of my NetDrives tool (which is open source too, btw), I discovered that there's no built-in NotifyIcon available within the WPF namespace - I had to fall back to the component of the Windows Forms namespace. So far so good, but I quickly started to miss quite a few features, including:

  • Rich ToolTips rather than text  
  • WPF context menus and popups
  • Command support and routed events 
  • Flexible data binding  
  • Rich balloon messages rather than the default messages provides by the OS

With the problem on the table, I started working on this pure-WPF solution in order to fill the gaps. And here we are Smile | :)

 

Contents

 

 

 

Article and Samples

This article briefly discusses the implementation and structure of the control and then describes the various features. The tutorials start with the common stuff (declaration, setting the icon, ToolTips etc.) and then dive into slightly more advanced scenarios (data binding, commands, events).

Due to the number of features of the control, this has become quite a reading. Still, you should be able to get started right away. You can explore the different features step by step, and the attached sample application closely follows the contents of this article.

Basically, you can immediately try out everything that is outlined in the tutorial part of this article, and you'll find all the sources in the Tutorials folder of the sample application:

 

wpf_notifyicon/Solution.png

 

Project Page / Alternatives 

Project Page  

I'll try to keep this article up-to-date, but the reference page for the control's development is here: http://www.hardcodet.net/wpf-notifyicon.

If you want to make sure the latest sources have been made available here, just have a look at the project page, or subscribe to the RSS feed on my blog in order to stay tuned about what's going on.

 

Alternative Projects

I would also like to mention that there's quite a few alternative solutions around. All but one I've seen so far are basically wrappers around the WinForms NotifyIcon, and they provide the basic functionality that you may know from your WinForms project. An incomplete list of noteworthy links: 

Control Implementation Overview 

Basically, the implementation can be divided into two areas:

  • The classes in the Interopnamespace contain code that configures the NotifyIcon via the Shell_NotifyIcon function of the Win32 API. These classes are used internally by the control. 
  • The classes in the project folder provide the WPF API. This is the public API that you'll be working with. The powerhorse here is the TaskbarIconclass, which represents your NotifyIcon. 

wpf_notifyicon/Classes.png

 

Win32 API - The Interop Namespace

 

Just like the WinForms NotifyIcon, this control is basically a wrapper around the Shell_NotifyIcon function of the Windows API. It does, however, support the latest improvements (up to Vista), including richer ToolTips (with a fallback mechanism for Windows xp) and custom icons for balloon messages.

In case you want to start your own implementation (be it WPF or not), you can basically take the code of the Interopnamespace along with the helper methods in the Utilclass and you should be good to go: The classes and enums there provide you with a clean and well documented façade to Shell_NotifyIcon and related classes.  If you want to invoke Shell_NotifyIcon, you can do so via the WriteIconDatamethod in the Utilclass:

/// Updates the taskbar icon with data provided by a given
/// <see cref="NotifyIconData"/> instance.
/// </summary>
/// <param name="data">Configuration settings for the NotifyIcon.</param>
/// <param name="command">Operation on the icon (e.g. delete the icon).</param>
/// <returns>True if the data was successfully written.</returns>
/// <remarks>See Shell_NotifyIcon documentation on MSDN for details.</remarks>
public static bool WriteIconData(ref NotifyIconData data, NotifyCommand command)
{
  return WriteIconData(ref data, command, data.ValidMembers);
}


/// <summary>
/// Updates the taskbar icon with data provided by a given
/// <see cref="NotifyIconData"/> instance.
/// </summary>
/// <param name="data">Configuration settings for the NotifyIcon.</param>
/// <param name="command">Operation on the icon (e.g. delete the icon).</param>
/// <param name="flags">Defines which members of the <paramref name="data"/>
/// structure are set.</param>
/// <returns>True if the data was successfully written.</returns>
/// <remarks>See Shell_NotifyIcon documentation on MSDN for details.</remarks>
public static bool WriteIconData(ref NotifyIconData data, NotifyCommand command,
                                 IconDataMembers flags)
{
  //do nothing if in design mode
  if (IsDesignMode) return true;

  data.ValidMembers = flags;
  lock (SyncRoot)
  {
    return WinApi.Shell_NotifyIcon(command, ref data);
  }
}

WPF API - The TaskbarIcon Class

As a user of the control, you don't have to deal with Win32 interna at all. The TaskbarIcon class represents the NotifyIcon, and it exposes a clean API that should feel familiar to every WPF developer. 

Here's an overview of the class' properties and events:

wpf_notifyicon/TaskbarIcon.png

There's a huge number of properties and events available, but don't worry - if you don't want to, you don't have to deal with most of them. Basically, the control provides you with functionality in the following areas, which are all optional (even the displayed icon itself):

  • Displaying an Icon in the tray area.
  • Showing ToolTips if the user hovers the mouse over the tray icon.
  • Opening a ContextMenu if the user clicks on the NotifyIcon.
  • Opening an interactive Popup control is the user clicks on the NotifyIcon.
  • Displaying balloon messages in the tray area in case of an event (either standard balloon tips or custom balloons).

 

 

 

Tutorial Part 1: The Basics

Hello NotifyIcon  

To get started, let's have a look at creating your first NotifyIcon. You can do this both programmatically and declaratively.

Creating the NotifyIcon in Code

//Note: XAML is suggested for all but the simplest scenarios
TaskbarIcon tbi = new TaskbarIcon();
tbi.Icon = Resources.Error;
tbi.ToolTipText = "hello world";

 

Creating the NotifyIcon in XAML

In order to declare the TaskbarIconin XAML, you will have to add the following namespace declaration to the header of your XAML file first:

xmlns:tb="http://www.hardcodet.net/taskbar"

 

Then just declare the TaskbarIconwith the tbprefix:

<Window
  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"
>
  <Grid>

    <!--
      in order to create a NotifyIcon, all you need is the
      namespace declaration (see above on line 4) and a simple
      declaration
    -->
    <tb:TaskbarIcon
      IconSource="/Icons/Error.ico"
      ToolTipText="hello world" />

  </Grid>
</Window>

The snippet above is all you need to display the following NotifyIcon in the tray area:

wpf_notifyicon/BasicDeclaration.png
 

Note: If you looked closely, you saw that in code, the Iconproperty was set, while in XAML, the icon image was set via the IconSourcedependency property. The difference between these two properties is that Iconis a standard property that takes a System.Drawing.Iconinstance, while IconSourceis a WPF  Dependency Property of type ImageSource, which is more suitable to be used in XAML. The outcome is the same, however: Setting IconSource automatically sets the Iconproperty.

 

Creating the NotifyIcon from a Resource Dictionary

 

This is basically a combination of code and markup, and the pattern I'd recommend for real-life  scenarios:

  • The TaskbarIconis declared in a XAML Resource Dictionary
  • It is looked up in code during application intialization 

This pattern allows you to separate the NotifyIcon from your application's windows and allows you to close all windows while your application still runs in the background. 

<ResourceDictionary 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">

  <!-- Globally declared notify icon -->
  <tb:TaskbarIcon x:Key="MyNotifyIcon"
                  IconSource="/Icons/Error.ico"
                  ToolTipText="hello world" />

</ResourceDictionary>

Once declared as a global resource, you can just look up your NotifyIcon using the FindResource method:  

public class App
{
  private TaskbarIcon tb;
  
  private void InitApplication()
  {
    //initialize NotifyIcon
    tb = (TaskbarIcon) FindResource("MyNotifyIcon");
  }
}    

An elegant solution to provide interactivity is to assign a view model to the NotifyIcon control by setting its DataContext in XAML or programmatically. Have a look at the windowless application sample in the download.

Changing Icon Visibility 

You can always show/hide the NotifyIcon in the tray area at runtime by setting the Visibilityproperty of the TaskbarIcon(which is set to Visibility.Visibleby default). Here's how to do it in XAML:  

<tb:TaskbarIcon
  IconSource="/Icons/Error.ico"
  Visibility="Collapsed" />

..and this is the corresponding C# code snippet:

TaskbarIcon tbi = new TaskbarIcon();
tbi.Icon = Resources.Error;
tbi.Visibility = Visibility.Collapsed;

 

Properly Closing the NotifyIcon

Once created, the NotifyIcon stays alive (visible or not) until the TaskbarIcon class is being disposed. This happens automatically if you shut down your application so you probably don't have to worry about that at all (if you have a single NotifyIcon, you can just hide if you don't need it). However, if you want to completely remove it at runtime, you should invoke the Disposemethod of the TaskbarIconclass.

 

 

Tutorial Part 2: ToolTips, Popups, Context Menus, Balloon Tips

The second part of the tutorials focuses on the different types of supported visuals. Starting from here, I will only show samples in XAML. I think it just makes more sense to do things declaratively than in code once the UI becomes a bit more involved.

Now let's have some shiny Smile | :)   

 

ToolTips

wpf_notifyicon/ToolTip.png

(A dynamic ToolTip in NetDrives which provides a quick status summary)

The TaskbarIconclass provides two ToolTip-related properties: 

  • The TrayToolTipproperty takes an arbitrary UIElementwhich is then displayed if the user hovers over the area. This can be a user control, a button, an image control or any other control.
    This is a very convenient way to display rich ToolTips. They are, however, are only supported starting from Windows Vista/2008 due to a limitation of the Win32 Shell_NotifyIcon function in earlier versions (xp / 2003). Of course, rich ToolTips also work fine on Windows 7.
  • The ToolTipTextproperty takes a string. It is displayed in two scenarios:
    • if the TrayToolTipproperty is not in use.
    • on older operating systems (xp/2003) that do not support rich ToolTips.
  • Accordingly, I'd recommend you always set the ToolTipTextproperty in order to have a fallback mechanism if your application runs on an older OS.

Note that ToolTips will only be displayed if no other control (Popup, Context Menu, or custom balloon tip) is currently displayed.


Attention: As TaskbarIconderives from FrameworkElement, it also provides a ToolTip property, which takes an arbitrary object. This property is being ignored - you should only use the TrayToolTipand ToolTipTextproperties!

ToolTip Creation 1: Declaring ToolTips Inline 

You can declare a custom ToolTip directly within the TaskbarIcondeclaration. Here's a simple sample that shows a semi-transparent Borderand a TextBlock:

<tb:TaskbarIcon
  IconSource="/Icons/Error.ico"
  ToolTipText="hello world">
  
  <!--
    We can use arbitrary UI elements as ToolTips.
    Let's use a semi-transparent border.
  -->
  <tb:TaskbarIcon.TrayToolTip>
    <Border
      Background="White"
      BorderBrush="Orange"
      BorderThickness="2"
      CornerRadius="4"
      Opacity="0.8"
      Width="160"
      Height="40">
      <TextBlock
        Text="hello world"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        />
     </Border>
  </tb:TaskbarIcon.TrayToolTip>
  
</tb:TaskbarIcon>

And this is the result:

wpf_notifyicon/SimpleToolTip.png

 

ToolTip Creation 2: Use a User Control

While declaring ToolTips inline certainly works, you might want to separate the ToolTip UI from the declaration of your NotifyIcon. As an example, let's recreate the ToolTip from above, but this time put the UI into a dedicated user control called SimpleUserControl:

<UserControl
  x:Class="Samples.Tutorials.ToolTips.SimpleUserControl"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  >

  <!-- a simple user control which displays a fixed text within a border -->
  <Border
    Background="White"
    BorderBrush="Orange"
    BorderThickness="2"
    CornerRadius="4"
    Opacity="0.8"
    Width="160"
    Height="40">
    <TextBlock
      Text="hello world"
      HorizontalAlignment="Center"
      VerticalAlignment="Center" />
  </Border>
  
</UserControl>

 ...and finally assign it to the NotifyIcon:

 

 

 

<tb:TaskbarIcon
  IconSource="/Icons/Error.ico"
  ToolTipText="hello world">

  <!-- assign user control as ToolTip -->
  <tb:TaskbarIcon.TrayToolTip>
    <local:SimpleUserControl />
  </tb:TaskbarIcon.TrayToolTip>

</tb:TaskbarIcon>

 

ToolTip Creation 3: Linking to a resource

In case you have declared your ToolTip control as a resource, the declaration becomes even simpler: 

<tb:TaskbarIcon
  IconSource="/Icons/Error.ico"
  ToolTipText="hello world"
  TrayToolTip="{StaticResource TheKeyOfMyToolTipControl}"  
  />

 

 

Popups  

Unlike a ToolTip, a Popup is only displayed if the user clicks on the NotifyIcon. It stays open if the user moves the mouse away from the tray area, but will close as soon as the user clicks somewhere else. Accordingly, you can provide interactive content  within a Popup, usually to provide some quick access to your application.

wpf_notifyicon/Popup.png 

Popup in NetDrives, which provides quick access to all configured shares. The user can select a share from the grid, double click a share, or open the grid's context menu.


Declaring a Popup works pretty much the same as setting a ToolTip does: You can assign arbitrary UIElement controls as Popups by setting the TrayPopupproperty. Lets recycle the inline ToolTip sample from above, but this time show a Buttonrather than a TextBlock:

<tb:TaskbarIcon
  IconSource="/Icons/Error.ico"
  ToolTipText="hello world">

  <!--
    We can use arbitrary UI elements as Popups.
    Popups stay open if the user moves away from the tray area
  -->
  <tb:TaskbarIcon.TrayPopup>
    <Border
      Background="White"
      BorderBrush="Orange"
      BorderThickness="2"
      CornerRadius="4"
      Width="160"
      Height="40">
      <Button
        Content="Click Me!"
        HorizontalAlignment="Center"
        VerticalAlignment="Center" />
    </Border>
  </tb:TaskbarIcon.TrayPopup>

</tb:TaskbarIcon>

 

The above markup produces the following (pretty ugly) result as soon as the user clicks on the NotifyIcon. But at least, it's a Popup: 

wpf_notifyicon/SimplePopup.png

 

Poup Activation

Per default, the Popup is opened if the left mouse button is being clicked, but you can use the PopupActivationproperty in order to control which mouse buttons activate your Popup. You can choose between left, middle, right mouse buttons, or a few common combinations.

<!-- also open popup on double click -->
<tb:TaskbarIcon
  TrayPopup="{StaticResource MyPopup}"  
  PopupActivation="LeftOrDoubleClick"
  />

 wpf_notifyicon/PopupActivation.png 

 

Context Menus

You can displays standard WPF context menus if the user clicks on the NotifyIcon:

wpf_notifyicon/ContextMenu.png

There's nothing special here - the ContextMenuproperty is directly derived from the FrameworkElementbase class: 

<tb:TaskbarIcon
  IconSource="/Icons/Error.ico"
  ToolTipText="hello world">

  <!-- Set a simple context menu  -->
  <tb:TaskbarIcon.ContextMenu>
    <ContextMenu
      Background="LightCoral">
      <MenuItem Header="First Menu Item" />
      <MenuItem Header="Second Menu Item" />
    </ContextMenu>
  </tb:TaskbarIcon.ContextMenu>

</tb:TaskbarIcon>

 

The above snippet creates the following output:

wpf_notifyicon/SimpleContextMenu.png

 

Context Menu Activation

Per default, the context menu is opened if the right mouse button is being clicked, but you can use the MenuActivationproperty in order to control which mouse buttons open the popup:

<!-- open menu on both left or right mouse click -->
<tb:TaskbarIcon
  ContextMenu="{StaticResource MyMenu}"  
  MenuActivation="LeftOrRightClick"
  />

Note: If you define conflicting values for PopupActivationand MenuActivation, the context menu always takes precedence over the Popup:

<!-- The popup will only show on double clicks - left click opens context menu -->
<tb:TaskbarIcon
  ContextMenu="{StaticResource MyMenu}"
  TrayPopup="{StaticResource MyPopup}"  
  MenuActivation="LeftOrRightClick"
  PopupActivation="LeftOrDoubleClick"
  />

 

Balloon Tips 

The NotifyIcon supports two kinds of balloon tips you can use to show an information in the tray area: 

  • Standard balloons, which are defined by the operations system.
  • Custom balloons - just like with ToolTips and Popups, you can turn arbitrary UIElements into balloon messages. This not only means that you can style the balloon to you liking, but thanks to the rich event model of the NotifyIcon, you can also create fancy animations.

 

Standard Balloons 

In order to display a standard balloon, the TaskbarIconclass provides two ShowBalloonTipmethods. One displays a balloon with a standard icon (Info, Warning, Error, None), the other overload shows the balloon with a custom System.Drawing.Iconinstead:

private void ShowStandardBalloon()
{
  string title = "WPF NotifyIcon";
  string text = "This is a standard balloon";

  //show balloon with built-in icon
  MyNotifyIcon.ShowBalloonTip(title, text, BalloonIcon.Error);

  //show balloon with custom icon
  MyNotifyIcon.ShowBalloonTip(title, text, MyNotifyIcon.Icon);


  //hide balloon
  MyNotifyIcon.HideBalloonTip();

}

Here's the output of the second method call that uses a custom icon:

wpf_notifyicon/StandardBalloon.png

 

Custom Balloons

In order to display a custom balloon tip, invoke the ShowCustomBalloonmethod of the TaskbarIconclass. ShowCustomBalloonnot only displays arbitrary UIElementinstances, but also provides some basic animations out of the box and an optional time span that defines a timeout for the balloon.

wpf_notifyicon/CustomBalloon.png
 

private void ShowCustomBalloon()
{
  FancyBalloon balloon = new FancyBalloon();

  //show balloon and close it after 4 seconds
  MyNotifyIcon.ShowCustomBalloon(balloon, PopupAnimation.Slide, 4000);
}

You can also close a balloon programmatically or abort the closing timer (e.g. if the user hovers over the balloon). Have a look at the showcase in the sample applications for a few scenarios. 

 

Tutorial Part 3: Commands, Events, and Data Binding 

The last part of this tutorial does not exactly require that your are a WPF-Ninja, but it's assumed that you are familiar with the concepts behind commands, routed events, or data binding.  In case you get lost, just post a question on the forum and I (and hopefully others, too) will try to point you in the right direction.

Built-in Command Support 

Commands provide a clean way to react to events on your NotifyIcon without having to hook up event listeners. TaskbarIconcurrently exposes two properties that allow you to assign a command:

  • LeftClickCommand 
  • DoubleClickCommand 

 

Let's implement a short sample that makes use of them... 

Implementing a Custom Command

To get started, here's a simple command called ShowMessageCommand, which just displays a message dialog. The dialog text is taken from the command parameter: 

/// <summary>
/// A simple command that displays the command parameter as
/// a dialog message.
/// </summary>
public class ShowMessageCommand : ICommand
{
  public void Execute(object parameter)
  {
    MessageBox.Show(parameter.ToString());
  }

  public bool CanExecute(object parameter)
  {
    return true;
  }

  public event EventHandler CanExecuteChanged;
}

 

Declaring the Command 

With the ShowMessageCommandin place, all that's left to do is hooking it up with the NotifyIcon. In the snippet below, I declared the command as a local resource:

<Window
  x:Class="Samples.Tutorials.Commands.CommandWindow"
  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"
  xmlns:local="clr-namespace:Samples.Tutorials.Commands"
  Height="300"
  Width="300">
  <Grid>
    
    <!-- declare the command as a local resource -->
    <Grid.Resources>
      <local:ShowMessageCommand
        x:Key="MessageCommand" />
    </Grid.Resources>

    <!-- declare the NotifyIcon and configure commands with parameters -->
    <tb:TaskbarIcon
      IconSource="/Icons/Error.ico"
      
      LeftClickCommand="{StaticResource MessageCommand}"
      LeftClickCommandParameter="Single left mouse button click."
      
      DoubleClickCommand="{StaticResource MessageCommand}"
      DoubleClickCommandParameter="Double click on NotifyIcon." />

  </Grid>
</Window>

You'll find this sample (along with all other snippets in this article) in the sample application.

 

LeftClickCommand Delay

Note that the LeftClickCommandfires after a short delay (as opposite to the DoubleClickCommandthat fires immediately). This is because there is a time span between a first click and a second click for the OS to consider the mouse action a double-click. The NotifyIcon is smart enough to wait this period in order to make sure the LeftClickCommandis only fired if the user does not click a second time within that period.

 

Data Binding in ToolTips, Popups, Context Menus, and Custom Balloons 

Binding to the TaskbarIconclass that manages your ToolTip, Popup, context menu, or balloon tip is pretty easy. There are two variants (which are both shown in the sample application):

  • You can bind implicitly through the data context of your custom control (if DataContextis not already in use). 
  • You can bind explicitly through the attached ParentTaskbarIconproperty. This property allows you to access the TaskbarIconeven if the DataContextis already in use. 

 

 

Implicit Binding through DataContext  

In order to simplify data binding scenarios for you, the TaskbarIconclass tries to set the DataContextof ToolTips, Popups, context menus and custom balloon messages according to the following rules: 

  1. If ToolTips, Popups, context menus, or custom ballons have a data context of their own, it is not being changed.
  2. If the DataContext is not in use:
    1. If the TaskbarIconhas a data context (its own DataContextproperty is not null), it assigns its data context to the DataContextproperties of ToolTips, Popups, context menus, and custom balloon tips.
    2. If the TaskbarIcondoes not have a data context (its own DataContextproperty is null), it assigns itself as the DataContextof ToolTips, Popups, context menus, and balloon tips. 



This mechanism provides you with a very simple solution to implicitly access either the TaskbarIconor its DataContextin your binding expressions.  As a simple example, lets revisit the inline ToolTip sample from the first tutorial, but this time, bind the output of the displayed TextBlockto the ToolTipText property of the NotifyIcon:

<tb:TaskbarIcon
  IconSource="/Icons/Error.ico"
  ToolTipText="hello world">

  <tb:TaskbarIcon.TrayToolTip>
    <Border>
      <!-- use a binding expression rather than fixed text -->
      <TextBlock
        Text="{Binding Path=ToolTipText}"
        HorizontalAlignment="Center"
        VerticalAlignment="Center" />
    </Border>
  </tb:TaskbarIcon.TrayToolTip>

</tb:TaskbarIcon>

If you compare the above snippet with the first ToolTip tutorial, you can see that only a single line was changed:

<TextBlock Text="{Binding Path=ToolTipText}" ... />

 

This binding statement works because the TaskbarIconclass became the DataContextof the TextBlockcontrol. This is what happens at runtime:

  • A Bordercontrol is assigned to the TrayToolTipproperty of the TaskbarIcon.
  • The NotifyIcon checks  whether the DataContextof this Bordercontrol is already set. This is not the case.
  • As a result, the TaskbarIconchecks whether it's own DataContextis set.
  • Because the TaskbarIconitself does not have a DataContexteither, it assigns itself as the DataContextof the Bordercontrol. 
  • The TextBlockis a child of the Bordercontrol. As such, it derives the DataContext. Accordingly, it can implicitly bind to the ToolTipTextproperty of the TaskbarIcon.

 

Explicit Binding: The ParentTaskbarIcon Attached Property

Another and more explicit solution is to to use the ParentTaskbarIconattached property. If a ToolTip, Popup, context menu, or a custom balloon is managed by TaskbarIcon, TaskbarIconassigns itself through this attached property.
You can access this property both in code or data binding expressions. As an example, here's the same ToolTip sample, this time explicitly accessing the NotifyIcon through the ParentTaskbarIconproperty:

<!-- This notifyicon has its DataContext set - implicit binding is not possible -->
<tb:TaskbarIcon
  x:Name="MyNotifyIcon2"
  DataContext="WPF IS GREAT: "
  IconSource="/Icons/Inactive.ico"
  ToolTipText="{Binding ElementName=txtToolTip, Path=Text}">

  <tb:TaskbarIcon.TrayToolTip>
  
    <!-- 
      Important: The attached property is assigned to the border!
      The NotifyIcon does not touch the underlying controls.
    -->
    <Border
      Background="White"
      BorderBrush="Orange"
      BorderThickness="2"
      CornerRadius="4"
      Opacity="0.8"
      Width="160"
      Height="40">
      <!-- Implicitly access the DataContext (which is a string this time)-->
      <TextBlock Text="{Binding}">
      <!-- Explicitly access the NotifyIcon -->
      <TextBlock
        Text="{Binding RelativeSource={RelativeSource FindAncestor,
                                       AncestorType={x:Type Border}},
               Path=(tb:TaskbarIcon.ParentTaskbarIcon).ToolTipText}"
        HorizontalAlignment="Center"
        VerticalAlignment="Center" />
      </TextBlock>
    </Border>
  </tb:TaskbarIcon.TrayToolTip>

</tb:TaskbarIcon>

 

 

 

 


Note the binding expression, wich is a bit more complex here in order to get to the attached property. The TextBlockneeds to resolve its parent Border(which was assigned the attached property) in order to get to the attached property: 

<TextBlock
    Text="{Binding RelativeSource={RelativeSource FindAncestor,
                                  AncestorType={x:Type Border}},
    Path=(tb:TaskbarIcon.ParentTaskbarIcon).ToolTipText}"
 />

 

Despite the additional complexity, this syntax has its advantages, as it is guaranteed that the attached property is always at your disposal, even if the DataContextis in use (e.g. in order to access your ViewModel).

 

Events 

 

Routed TaskbarIcon Events 

The TaskbarIconclass provides an array of routed events  - there's pretty much an event for everything that happens with the NotifyIcon or related controls. For a sample on how to use these events declaratively to trigger animations, check out the tutorial in the sample application. 

wpf_notifyicon/EventTutorial.png

 

Attached Events for ToolTips, Popups, and Balloons

This is one of the fancy WPF features of the control. Basically, attached events are events that are fired on your custom ToolTips, Popups, and Balloon controls without requiring you to write a single line of code. This is a very clean mechanism to trigger animations in these controls on a purely declarative basis. I won't go into the details here, but rather point you to these resources: 

 

  • The sample application uses the PopupOpenedattached event in order to trigger an animation in the popup (rotating icon) every time it's being displayed.
    The custom balloon sample uses several attached events to fade in and out. 
  • I recently published a general tutorial on using attached events to trigger animations in Blend, along with another sample. You find it here.

 

Conclusion

I hope this article along with the attached samples will help you to a smooth start. I really enjoyed writing the control, and I hope it will make a valuable addition to your toolbox. Happy coding! Smile | :)

 

 

History   

(A detailed changelog is part of the solution)

1.0.5 (2013.11.20)
Fixes issues with x64, Win 8, Focus

1.0.4 (2009.09.21)
Proper focus for popups, improved compatibility for WinForms scenarios.

1.0.3 (2009.07.02)
Proper support for routed commands including command targets. 

1.0.2 (2009.05.18)
Fixed possibly wrong DataContext assignment when intitializing ContextMenus.

1.0.1 (2009.05.15)
Initial CodeProject released

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Philipp Sumi
Architect I'm a gun for hire
Switzerland Switzerland
Philipp is an independent software engineer with great love for all things .NET.
He lives in Winterthur, Switzerland and his home on the web is at http://www.hardcodet.net.

You may also be interested in...

Comments and Discussions

 
GeneralMy vote of 5 Pin
Amer Bakeer6-Dec-13 10:03
memberAmer Bakeer6-Dec-13 10:03 
GeneralRe: My vote of 5 Pin
Philipp Sumi6-Dec-13 23:01
memberPhilipp Sumi6-Dec-13 23:01 
QuestionDynamic Context Menu Pin
mikeh3626-Nov-13 6:42
membermikeh3626-Nov-13 6:42 
AnswerRe: Dynamic Context Menu Pin
Philipp Sumi26-Nov-13 7:56
memberPhilipp Sumi26-Nov-13 7:56 
GeneralRe: Dynamic Context Menu Pin
mikeh3626-Nov-13 11:04
membermikeh3626-Nov-13 11:04 
GeneralRe: Dynamic Context Menu Pin
Philipp Sumi27-Nov-13 2:41
memberPhilipp Sumi27-Nov-13 2:41 
QuestionXAMLParseException Pin
eMZi076716-Nov-13 9:46
membereMZi076716-Nov-13 9:46 
AnswerRe: XAMLParseException Pin
Philipp Sumi17-Nov-13 7:47
memberPhilipp Sumi17-Nov-13 7:47 
QuestionContextMenu dont work Pin
sh1omi8-Nov-13 18:51
membersh1omi8-Nov-13 18:51 
AnswerRe: ContextMenu dont work Pin
Philipp Sumi17-Nov-13 12:18
memberPhilipp Sumi17-Nov-13 12:18 
QuestionHandling ContextMenuOpening event Pin
Member 103844176-Nov-13 12:53
memberMember 103844176-Nov-13 12:53 
AnswerRe: Handling ContextMenuOpening event Pin
Philipp Sumi17-Nov-13 11:55
memberPhilipp Sumi17-Nov-13 11:55 
Question2Way DataBinding on TextBox Pin
ToniMa6-Nov-13 3:07
memberToniMa6-Nov-13 3:07 
AnswerRe: 2Way DataBinding on TextBox Pin
Philipp Sumi17-Nov-13 7:45
memberPhilipp Sumi17-Nov-13 7:45 
Hi there

I'm working on an update, and ToolTips will become interactive, too. For your current problem: Can you get me a (non-)working example I could debug?

Cheers,
Philipp

(btw: if you need just ToolTips, have a look at the interactive ToolTip control I just released.)
NetDrives - Open Source Network Share Management Awesomeness

QuestionRe: 2Way DataBinding on TextBox Pin
ToniMa8-Jan-15 20:10
memberToniMa8-Jan-15 20:10 
QuestionError on including namespace to XAML Pin
Santiago Fabian10-Sep-13 20:56
memberSantiago Fabian10-Sep-13 20:56 
AnswerRe: Error on including namespace to XAML Pin
eMZi076716-Nov-13 9:50
membereMZi076716-Nov-13 9:50 
QuestionBinding for mvvm not working in traypopup Pin
victorInsync30-Aug-13 20:53
membervictorInsync30-Aug-13 20:53 
GeneralGood work! But not sure about NotifyIconData size Pin
datenkabel16-Aug-13 1:42
memberdatenkabel16-Aug-13 1:42 
GeneralRe: Good work! But not sure about NotifyIconData size Pin
Philipp Sumi17-Nov-13 7:36
memberPhilipp Sumi17-Nov-13 7:36 
QuestionTrying to get the databinding to work Pin
Darrin Dyson7-Aug-13 12:43
memberDarrin Dyson7-Aug-13 12:43 
QuestionBinding to the IconSource property Pin
Harriet0017-Aug-13 2:59
memberHarriet0017-Aug-13 2:59 
AnswerRe: Binding to the IconSource property Pin
tobster8-Aug-13 23:13
membertobster8-Aug-13 23:13 
GeneralMy vote of 5 Pin
Detlef Ziehlke1-Aug-13 23:46
memberDetlef Ziehlke1-Aug-13 23:46 
SuggestionFixes to easily support 3.5 -> 4.5 Pin
PaulVilevac30-Jul-13 14:42
memberPaulVilevac30-Jul-13 14:42 
GeneralRe: Fixes to easily support 3.5 -> 4.5 Pin
echosong3-Sep-13 17:47
memberechosong3-Sep-13 17:47 
GeneralRe: Fixes to easily support 3.5 -> 4.5 Pin
Member 986221716-Oct-13 4:18
memberMember 986221716-Oct-13 4:18 
GeneralRe: Fixes to easily support 3.5 -> 4.5 Pin
Philipp Sumi27-Nov-13 13:25
memberPhilipp Sumi27-Nov-13 13:25 
GeneralRe: Fixes to easily support 3.5 -> 4.5 Pin
Member 986221727-Nov-13 23:18
memberMember 986221727-Nov-13 23:18 
GeneralRe: Fixes to easily support 3.5 -> 4.5 Pin
Philipp Sumi28-Nov-13 3:29
memberPhilipp Sumi28-Nov-13 3:29 
GeneralRe: Fixes to easily support 3.5 -> 4.5 Pin
Philipp Sumi13-Nov-13 1:45
memberPhilipp Sumi13-Nov-13 1:45 
GeneralCongratulations Pin
Flavio_Henrique24-Jul-13 9:38
memberFlavio_Henrique24-Jul-13 9:38 
GeneralMy vote of 5 Pin
StoneFactory2-Jul-13 0:23
memberStoneFactory2-Jul-13 0:23 
QuestionProbleme with re using the same popup Pin
matriiixo27-Jun-13 4:14
membermatriiixo27-Jun-13 4:14 
GeneralMy vote of 5 Pin
CoderHead26-Jun-13 2:20
memberCoderHead26-Jun-13 2:20 
Questionopen the menu items using the keyboard shortcut keys. Pin
vinodsujata5-Jun-13 0:25
membervinodsujata5-Jun-13 0:25 
GeneralMy vote of 5 Pin
Javad Amiry18-May-13 3:54
memberJavad Amiry18-May-13 3:54 
QuestionForce tray icon to be shown and not under "hidden icons" Pin
Vamp109884-May-13 11:20
memberVamp109884-May-13 11:20 
GeneralMy vote of 5 Pin
kaardinator22-Apr-13 21:52
memberkaardinator22-Apr-13 21:52 
QuestionAssembly not signed. Signed version available? Pin
AnthonyKilhoffer22-Apr-13 5:31
memberAnthonyKilhoffer22-Apr-13 5:31 
AnswerRe: Assembly not signed. Signed version available? Pin
Steve021226-Nov-14 4:54
memberSteve021226-Nov-14 4:54 
QuestionWindow restore, and attaching commands to the context menu items ??? Pin
Barry ONeill14-Apr-13 18:49
memberBarry ONeill14-Apr-13 18:49 
AnswerRe: Window restore, and attaching commands to the context menu items ??? Pin
Ag.Smith25-Feb-14 0:16
memberAg.Smith25-Feb-14 0:16 
GeneralMy vote of 5 Pin
mbahri5-Mar-13 5:01
membermbahri5-Mar-13 5:01 
GeneralMy vote of 5 Pin
ChrisBence26-Feb-13 10:57
memberChrisBence26-Feb-13 10:57 
QuestionToolBarText Position Pin
gideonrv16-Feb-13 8:44
membergideonrv16-Feb-13 8:44 
GeneralMy vote of 5 Pin
Gil Yoder11-Feb-13 17:38
memberGil Yoder11-Feb-13 17:38 
QuestionThere is any MouseLeave or MouseHoover event? Pin
Tóth Antal30-Jan-13 23:43
memberTóth Antal30-Jan-13 23:43 
Question64 bit version? Pin
Дима Милых24-Jan-13 1:44
memberДима Милых24-Jan-13 1:44 
QuestionKeyboard shortcuts / hotkeys on TaskbarIcon.ContextMenu ? Pin
EggnogSaber14-Jan-13 1:03
memberEggnogSaber14-Jan-13 1:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150804.4 | Last Updated 23 Nov 2013
Article Copyright 2009 by Philipp Sumi
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid