Out of the box, .NET doesn't have any kind of support for animated icons, which is fair enough as its not something you find yourself in need of very often. However, recently I wrote an application that lives in the tray area of the taskbar, and I ended up using a set of color-coded icons to give a visual clue to the user on the state of the application (connected, disconnected, error etc). I found myself wanting to use an animated icon for when the application was doing work, to differentiate it from the idle states.
What I came up with, was a component I've called the IconAnimator. The IconAnimator basically allows you to specify a control for which it will animate the Icon of (which can be any component with a public mutable Icon property - a Form or NotifyIcon usually), and exposes Start and Stop methods for controlling the animation. The frames of the animation is stored in an ImageList, which has a rather nice "side-effect" - you dont have to use .ico files, it will work just as well with any kind of image type the ImageList supports. Credit to Ryan Farley for working out how to get Icons out of an ImageList :)
To use the IconAnimator, just drop it onto a Form along with an ImageList component:
Next, set its TargetComponent to the component that you want to animate the Icon for (in this example, the Form itself), and point the Frames property to the ImageList:
Finally, add the frames of the animation to the ImageList:
With everything set up, you can then simply call the Start() and Stop() methods on the IconAnimator in your code whenever you want to start/stop the animation.
Here is the source code, feel free to use it in your own projects:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Reflection;
using System.Runtime.CompilerServices;
public class IconAnimator : Component
{
#region Fields
private Component _target;
Timer _timer;
PropertyInfo _iconProperty;
private ImageList _frames;
int _currentIndex = 0;
#endregion
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="IconAnimator"/> class.
/// </summary>
public IconAnimator()
{
_timer = new Timer();
_timer.Tick += new EventHandler(_timer_Tick);
}
#endregion
#region Animation
[MethodImpl(MethodImplOptions.Synchronized)]
void _timer_Tick(object sender, EventArgs e)
{
Icon icon = Icon.FromHandle((this.Frames.Images[_currentIndex] as Bitmap).GetHicon());
IDisposable previousIcon = _iconProperty.GetValue(this.TargetComponent, null) as IDisposable;
_iconProperty.SetValue(_target, icon, null);
if (null != previousIcon)
{
previousIcon.Dispose();
}
++_currentIndex;
if (_currentIndex >= this.Frames.Images.Count)
{
_currentIndex = 0;
}
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the component whose icon should be animated by the IconAnimator.
/// </summary>
/// <value>The component to animate.</value>
public Component TargetComponent
{
get { return _target; }
set
{
if (null == value)
{
_target = null;
}
else
{
_iconProperty = value.GetType().GetProperty("Icon");
if (null == _iconProperty || _iconProperty.PropertyType != typeof(Icon))
{
throw new ArgumentException("Unsupported Control type. " +
"Must be a control with a public Icon property of type Icon.");
}
_target = value;
}
}
}
/// <summary>
/// Gets or sets the frames of the animation
/// </summary>
/// <value>The frames.</value>
public ImageList Frames
{
get { return _frames; }
set { _frames = value; }
}
/// <summary>
/// Gets or sets the interval between each frame in the animation.
/// </summary>
/// <value>The interval in miliseconds.</value>
public int Interval
{
get { return _timer.Interval; }
set { _timer.Interval = value; }
}
#endregion
/// <summary>
/// Starts the animation.
/// </summary>
public void Start()
{
if (null == this.TargetComponent)
{
throw new InvalidOperationException("Cannot start animating when ControlToAnimate is null");
}
if (null == this.Frames || this.Frames.Images.Count == 0)
{
throw new InvalidOperationException("Cannot start animating when Frames is null or holds zero images");
}
_timer.Start();
}
/// <summary>
/// Stops the animation.
/// </summary>
public void Stop()
{
_timer.Stop();
}
}