Click here to Skip to main content
Click here to Skip to main content

WPF Taskbar Notifier - A WPF Taskbar Notification Window

By , 22 Jan 2008
 
Screenshot of the demo application

Introduction

This WPF Taskbar Notifier is a WPF window that opens and closes using a storyboard animation. It can be used to notify a user when some event of interest has occurred.

When Notify() is called, the window moves up from the bottom right corner of the desktop (just above the taskbar when the taskbar is there). Once open, the window stays open for a configurable amount of time before it begins hiding again. The speed for opening and hiding are also configurable. The window will remain open as long as the mouse is over it.

Additionally, a WPF wrapper for the Windows Forms NotifyIcon is included to make it easy to add an icon to the system tray. This icon can come in handy for adding a user interface for re-opening, configuring, and exiting the WPF Taskbar Notifier. The NotifyIcon wrapper was written by Mariano Omar Rodriguez and posted on his blog here.

To see the WPF Taskbar Notifier in action, download the demo executable and give it a try!

Background

There are at least several other C# implementations of a window that pops up from the taskbar. None of the ones I've seen offer a WPF window.

Using the Code

TaskbarNotifier.cs contains the TaskbarNotifier class, which is the popup WPF window. TaskbarNotifier defines no window content because anyone using it will want to define their own application specific content. In the demo source code, the ExampleTaskbarNotifier class uses TaskbarNotifier as a base class and defines its content in ExampleTaskbarNotifier.xaml. What content you decide to put into your own subclass of TaskbarNotifier is up to you.

There are several public properties and methods that allow you to control the window's behavior.

  • int OpeningMilliseconds - The number of milliseconds it takes for the window to open from its fully hidden position.
  • int HidingMilliseconds - The number of milliseconds it takes for the window to hide from its fully open position.
  • int StayOpenMilliseconds - The number of milliseconds the window will stay open once it reaches its fully open position. Once this time has elapsed, it will begin hiding.
  • int LeftOffset - The number of pixels the window should be offset from the left side of the desktop. This allows the window to be shifted horizontally, if the default (extreme bottom right corner) is not desired.
  • void Notify() - Tells the window to open.
  • void ForceHidden() - Immediately puts the window into its hiding position.

As mentioned above, TaskbarNotifier should be subclassed in order to add your own content. In the example, the main application window itself is a standard window, not a TaskbarNotifier window. The main window creates and displays the ExampleTaskbarNotifier window in its constructor. At this point it is not visible to the user, because it is too low on the desktop to see.

public Window1()
{
    this.taskbarNotifier = new ExampleTaskbarNotifier();
    InitializeComponent();
    this.taskbarNotifier.Show();
}

The application specific content of the subclasses TaskbarNotifier window can be defined in XAML like any other WPF window:

<tn:TaskbarNotifier x:Class="WPFTaskbarNotifierExample.ExampleTaskbarNotifier"
    xmlns:tn="clr-namespace:WPFTaskbarNotifier;assembly=WPFTaskbarNotifier"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF Taskbar Notifier Example" Height="160"  Width="300"
    >

    <!-- insert your XAML here -->

</tn:TaskbarNotifier>

Because the TaskbarNotifier window hides itself completely, it seemed necessary to include some way of opening, configuring, and exiting it. I've included Mariano Omar Rodriguez's NotifyIcon wrapper to allow a system tray icon to be instantiated in XAML. While the demo application does not use the NotifyIcon's balloon tips for anything, it does demonstrate how a system tray icon can be used in conjunction with the Taskbar Notifier.

Here is how the NotifyIcon is declared in the example's XAML:

<tn:NotifyIcon x:Name="NotifyIcon" Text="Example Notifier" 
        Icon="Resources/UFO.ico" MouseDoubleClick="NotifyIcon_DoubleClick">
  <tn:NotifyIcon.ContextMenu>
    <ContextMenu>
      <MenuItem Header="Open" Click="NotifyIconOpen_Click" />
      <MenuItem Header="Configure..." Click="NotifyIconConfigure_Click" />
      <Separator/>
      <MenuItem Header="Exit" Click="NotifyIconExit_Click" />
    </ContextMenu>
  </tn:NotifyIcon.ContextMenu>
</tn:NotifyIcon>

In your application, whenever it makes sense for the TaskbarNotifier to pop up, its Notify() method can be called.

How it Works

The TaskbarNotifier uses a single Storyboard based on the window's Top property, and a DoubleAnimation.

this.animation = new DoubleAnimation();
Storyboard.SetTargetProperty(this.animation, new PropertyPath(Window.TopProperty));
this.storyboard = new Storyboard();
this.storyboard.Children.Add(this.animation);
this.storyboard.FillBehavior = FillBehavior.Stop;

By animating Top, the window's location moves. The size of the window is never changed, as this could potentially change the way the window's contents are organized. The window is simply moved out of view.

In the code, when a change in movement is required the Storyboard is stopped, the To and Duration properties of the DoubleAnimation are altered, and the Storyboard is told to Begin again. For example, if the window is Hiding and the user moves the cursor over the window, the window stops hiding and changes its state to Opening. The Duration is calculated based on the current window location to ensure the desired opening/hiding rate.

The private DisplayState property drives the movement of the window. The possible values of DisplayState are defined in the following enumeration:

private enum DisplayStates
{
    Opening,
    Opened,
    Hiding,
    Hidden
}

Whenever DisplayState is altered, the OnDisplayStateChanged method is called:

private DisplayStates DisplayState
{
    get { return this.displayState; }
    set
    {
        if (value != this.displayState)
        {
            this.displayState = value;

            // Handle the new state.
            this.OnDisplayStateChanged();
        }
    }
}

OnDisplayStateChanged simply stops the current animation and handles DisplayState based on each of the four possible DisplayStates.

For example, here is how the Storyboard is configured and re-started when the window is told to open:

// Because the window may already be partially open, the rate at which
// it opens may be a fraction of the normal rate.
// This must be calculated.
int milliseconds = this.CalculateMillseconds(this.openingMilliseconds, this.openedTop);

// Reconfigure the animation.
this.animation.To = this.openedTop;
this.animation.Duration = new Duration(new TimeSpan(0, 0, 0, 0, milliseconds));

// Set the specific completed event handler.
this.storyboard.Completed += arrivedOpened;

// Start the animation.
this.storyboard.Begin(this, true);

A DispatcherTimer is used to trigger the hiding of the window once it has been in the open state for the duration indicated by StayOpenMilliseconds.

Here is how the DispatcherTimer is created:

// Prepare the timer for how long the window should stay open.
this.stayOpenTimer = new DispatcherTimer();
this.stayOpenTimer.Interval = TimeSpan.FromMilliseconds(this.stayOpenMilliseconds);
this.stayOpenTimer.Tick += new EventHandler(this.stayOpenTimer_Elapsed);

When the stayOpenTimer elapses, the timer is stopped and as long as the mouse is not over it, the window is told to hide. This is accomplished by setting the DisplayState to DisplayStates.Hiding:

private void stayOpenTimer_Elapsed(Object sender, EventArgs args)
{
    // Stop the timer because this should not be an ongoing event.
    this.stayOpenTimer.Stop();

    if (!this.IsMouseOver)
    {
        // Only start closing the window if the mouse is not over it.
        this.DisplayState = DisplayStates.Hiding;
    }
}

For more details, download the source code and check it out.

History

  • December 2007: Initial creation
  • 23 Jan 2008: Quick update to fix some visual problems

License

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

About the Author

Buzz Weetman
Software Developer
United States United States
Member
software engineer

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionEmpty messages popping upmemberchampi5 Apr '10 - 22:22 
Sometimes the application pops up with the empty title and empty message. Could you please let me how can we avoid this?
GeneralContext Menu does not disappear when clicked somewhere elsememberRobert Veringa1 Apr '10 - 1:57 
The context menu is not disappearing if you click somewhere else on the screen. Someone noticed that? Maybe a solution? It is driving me crazy!
Please help

GeneralExcellentmemberIan Shlasko17 Mar '10 - 10:27 
Works like a charm, pretty much as-is (Just the TaskbarNotifier class, not the icon)... Just had to add one method to manually slide it back down when the user responds to the message (As opposed to ForceHidden, which instantly hides it).
 
I encountered both the flickering and alt+tab issues below, and found easy solutions for both:
 
1) The flickering only happens if you use transparency. Shut that off, and it's nice and smooth.
 
2) To get it out of the Alt+Tab, just set it up as a child of your app's main window (If possible) by setting its Owner property
Proud to have finally moved to the A-Ark. Which one are you in?
Author of Guardians of Xen (Sci-Fi/Fantasy novel)

GeneralRe: ExcellentmemberGreg8627 Mar '10 - 22:48 
Hello,
 
For transparency, indeed it works well if that is shutted off.
 
But in my project, I would like to make an alert with round corner (like this : [myAlert])
 
The problem is, to make round corner and the close cross in that position, I do not have the choice to turn on the transparency.
 
Is there a way to bypass it ?
 
I have already seen that if I put in commentar the method "BringToTop", it works well. But with this solution, the alert is not on the foreground anymore.
 
Thanks in advance for you answers.
GeneralNotify icon appears but Not the PopupmemberMember 407644318 Aug '09 - 6:17 
I tried WpfNotifierExample in two different PC with Windows Vista - in One computer the popup appears and also the notify icon, in the other one (always with Windows Vista) the icon appears but the window does not popup. (may be it's something related to the animations ?) The Framework I AM USING is 3.5 SP1
 

 
HAS ANYONE IDEA WHY THIS HAPPENS?
GeneralHide Notification Window from Alt-TabmemberIntraRELY24 May '09 - 15:41 
I noticed that the window shows up in Alt-Tab, but w/ some sort of default Icon.
 
Any way of working around this as this seems as a problem everyone will have whether they noticed and sure they figured something out. It is not as easy as Hiding icon in taskbar?
GeneralRe: Hide Notification Window from Alt-TabmemberBuzz Weetman24 May '09 - 15:50 
Good find. I don't have a solution at this time.
There is a newer WPF notify icon code project here:
 
WPF NotifyIcon[^]
 
I wonder if that behaves better.
Let me know if you try it.
GeneralWindow Height=Auto doesnt adjust notification window heightmemberIntraRELY14 May '09 - 0:21 
very similar to your sample I have an observable collection of a custom object we have for our application. There is a ListView to which we have the bound collection. Depending on how many items are bound to the ListView the size needs to adjust accordingly.
 
The only way I can get it to work is to hard code the window level properties, setting to Auto doesnt dynamically increase the size. We are being notified of an arbitrary event, when there are two events being notified at the same time is the only time this prevents itself, but cannot get it to size correctly.
 
I tried to set +/- on the CollectionViewSource Filter event handler (this is where items are determined whether to be added or not) and when an item is added I tried to increase the height.
 
Not sure what else I could do.
 
TIA,
 
STeve
GeneralRe: Window Height=Auto doesnt adjust notification window heightmemberBuzz Weetman14 May '09 - 2:33 
I'm sorry I can't currently spend time on this.
Can you successfully create a plain old WPF window and have it grow the way you want?
Getting that working might help you debug your problem.
QuestionNot working with VS2008 sp1 on Vista sp1?memberdeerchao26 Dec '08 - 0:35 
No popup window shown.
 
System.Windows.Media.Animation Warning: 6 : Unable to perform action because the specified Storyboard was never applied to this object for interactive control.; Action='Stop'; Storyboard='System.Windows.Media.Animation.Storyboard'; Storyboard.HashCode='15586314'; Storyboard.Type='System.Windows.Media.Animation.Storyboard'; TargetElement='WPFTaskbarNotifierExample.ExampleTaskbarNotifier'; TargetElement.HashCode='26756241'; TargetElement.Type='WPFTaskbarNotifierExample.ExampleTaskbarNotifier'

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 23 Jan 2008
Article Copyright 2008 by Buzz Weetman
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid