Overview
Animated tray icons are a useful way of alerting users of changes to your applications state. Unfortunately the .NET frameworks tray icon offering doesn’t support animation so I decided to write a reusable component that extends the tray icon to incorporate the desired functionality. Another notable feature of this implementation is that it supports the 24×24 Windows 7 tray icons as opposed to others that rely on the scaling the 16×16 size icons up.
Download the control & sample project
Extending the non-extendable
The .NET TrayIcon class is sealed and therefore non-extendable so I have wrapped it (and some of it’s core properties and methods) within a new component to achieve extension.
Visual Studio Design Time Support
I have also made the component designer compliant by adding the relevant XML documentation markup and property definitions.
The Control Code
[AnimatedNofifyIcon.cs]
/* * C# Animated Notify Icon Component * * @package uk.co.codeblog.csharp.controls.AnimatedNotifyIcon * @author Oliver Green* @copyright Copyright (c) 2009-2012 CodeBlog (http://www.codeblog.co.uk) * @license Creative Commons Attribution-ShareAlike 3.0 Unported License. (http://creativecommons.org/licenses/by-sa/3.0/) * Version: 0.1 $Revision: 350 $ * Date: $Date: 2012-01-04 23:27:28 +0000 (Wed, 04 Jan 2012) $ * */ using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Text; using System.Windows.Forms; using System.Drawing; namespace uk.co.codeblog.csharp.controls { public partial class AnimatedNotifyIcon : Component { /* Timer to control the animation */ Timer _t = new Timer(); /* Our 'filstrip' of icons to build the animation from */ Icon[] _icons; /* Which index of the film strip are we currently on? */ int _cIndex = 0; /* How many times have we looped the animation so far? */ int _loopCount = 1; /* How many times should we loop the animation for? 0 = infinite */ int _loopNo = 0; /* * Properties * Most of which wrap the NotifyIcons properties on a basic level * (If you want events you'll have to reference the inner NotifyIcon * object */ /// The text that will be displaid when the mouse hovers over the icon [CategoryAttribute("Appearance"), DescriptionAttribute("The text that will be displaid when the mouse hovers over the icon")] public string Text { get { return _notifyIcon.Text; } set { _notifyIcon.Text = value; } } ///The icon to associate with the balloon ToolTip [CategoryAttribute("Appearance"), DescriptionAttribute("The icon to associate with the BalloonTip")] public ToolTipIcon BalloonTipIcon { get { return _notifyIcon.BalloonTipIcon; } set { _notifyIcon.BalloonTipIcon = value; } } ///The text to associate with the balloon ToolTip [CategoryAttribute("Appearance"), DescriptionAttribute("The text to associate with the balloon ToolTip")] public string BalloonTipText { get { return _notifyIcon.BalloonTipText; } set { _notifyIcon.BalloonTipText = value; } } ///The title to associate with the balloon ToolTip [CategoryAttribute("Appearance"), DescriptionAttribute("The title to associate with the balloon ToolTip")] public string BalloonTipTitle { get { return _notifyIcon.BalloonTipTitle; } set { _notifyIcon.BalloonTipTitle = value; } } ///The shortcut menu to show when the user right-clicks on the icon [CategoryAttribute("Behavior"), DescriptionAttribute("The shortcut menu to show when the user right-clicks on the icon")] public ContextMenuStrip ContextMenuStrip { get { return _notifyIcon.ContextMenuStrip; } set { _notifyIcon.ContextMenuStrip = value; } } ///Determines whether the control is visible or hidden [CategoryAttribute("Behavior"), DescriptionAttribute("Determines whether the control is visible or hidden")] public Boolean Visible { get { return _notifyIcon.Visible; } set { _notifyIcon.Visible = value; } } ///Gets the underlying NotifyIcon control [CategoryAttribute("Misc"), DescriptionAttribute("Gets the underlying NotifyIcon control")] public NotifyIcon NotifyIcon { get { return _notifyIcon; } } ///Sets the number of times for the animation to loop (0 = Infinite) [CategoryAttribute("Behavior"), DescriptionAttribute("Sets the number of times for the animation to loop (0 = Infinite)")] public int Loop { get { return _loopNo; } set { _loopNo = value; } } ///Sets the animation frame rate (FPS) [ CategoryAttribute("Behavior"), DescriptionAttribute("Sets the animation frame rate (FPS)")] public int FrameRate { get { return (1000 / _t.Interval); } set { int interval = (int) Math.Ceiling(Convert.ToDouble(1000 / value)); if (interval > 0) { _t.Interval = interval; } else { _t.Interval = 4; } } } ///Returns whether the animation is running or not [CategoryAttribute("Misc"), DescriptionAttribute("Returns whether the animation is running or not")] public Boolean IsRunning { get { return _t.Enabled; } } public AnimatedNotifyIcon() { InitializeComponent(); InitializeIcon(); } public AnimatedNotifyIcon(IContainer container) { container.Add(this); InitializeComponent(); InitializeIcon(); } ///Sets up the tray icon protected void InitializeIcon() { _t.Interval = 250; _t.Tick += ChangeIcon; } ///Changes the icon on timer protected void ChangeIcon(object sender, EventArgs e) { if (_loopNo == 0 || _loopCount <= _loopNo) { _cIndex++; if (_cIndex >= _icons.Length) { _cIndex = 0; _loopCount++; } _notifyIcon.Icon = _icons[_cIndex]; } else { _loopCount = 1; this.Stop(); } } ///Starts the animation public void Start() { _t.Start(); } ///Stops the animation public void Stop() { _t.Stop(); } ///Displays a balloon ToolTip in the taskbar for a specified period ///Time period, in millisecods, the balloon should display for public void ShowBalloonTip(int Timeout) { _notifyIcon.ShowBalloonTip(Timeout); } ///Displays a balloon ToolTip in the taskbar for a specified period ///Time period, in millisecods, the balloon should display for ///The title to display on the balloon tip ///The text to display on the balloon tip ///One of the System.Windows.Forms.ToolTipIcon values public void ShowBalloonTip(int Timeout, string TipTitle, string TipText, ToolTipIcon TipIcon) { _notifyIcon.ShowBalloonTip(Timeout, TipTitle, TipText, TipIcon); } ///Sets the animation frames ///Array of icons to form animation ///Sets the NotifyIcons current icon to the first icon in the Array public void SetAnimationFrames(Icon[] Icons, Boolean MoveToFirstFrame = true) { if (Icons.Length > 0) { _icons = Icons; if (MoveToFirstFrame) { _notifyIcon.Icon = Icons[0]; _cIndex = 0; } } } } }
[AnimatedNofifyIcon.Designer.cs]
/* * Demo Form * * @package uk.co.codeblog.csharp.controls.AnimatedNotifyIcon * @author Oliver Green* @copyright Copyright (c) 2009-2012 CodeBlog (http://www.codeblog.co.uk) * @license Creative Commons Attribution-ShareAlike 3.0 Unported License. (http://creativecommons.org/licenses/by-sa/3.0/) * Version: 0.1 $Revision: 350 $ * Date: $Date: 2012-01-04 23:27:28 +0000 (Wed, 04 Jan 2012) $ * */ using System.Drawing; namespace uk.co.codeblog.csharp.controls { [ToolboxBitmapAttribute(typeof(AnimatedNotifyIcon), "AnimatedNotifyIcon.ico")] partial class AnimatedNotifyIcon { /// /// Required designer variable. /// private System.ComponentModel.IContainer components = null; ////// Clean up any resources being used. /// /// true if managed resources should be disposed; otherwise, false. protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code ////// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this._notifyIcon = new System.Windows.Forms.NotifyIcon(this.components); // // trayIcon // this._notifyIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info; this._notifyIcon.Text = "trayIcon"; this._notifyIcon.Visible = true; } #endregion private System.Windows.Forms.NotifyIcon _notifyIcon; } }







