Windows Forms IconAnimator

An entry about windows forms Publication date 26. March 2007 13:25

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:

Components

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:

IconAnimator property window

Finally, add the frames of the animation to the ImageList:

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();
}
}

Currently rated 3.8 by 9 people

  • Currently 3.777778/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Powered by BlogEngine.NET 1.4.5.0

Welcome!

My name is Fredrik Kalseth, and this is my blog - thanks for visiting! I am fortunate enough to work with what I love for a living, and this blog is essentially the biproduct of that.

I work as a senior consultant for Capgemini, and am also an active participant in the Norwegian .NET community, as an avid attendee but also as a speaker (most recently at NNUG and MSDN Live).

As a developer, I have a wide circle of interest. My primary passion is for agile, test-driven development, with focus on best practices and clean code. That said, I also love to work on the frontend, especially with web development.

On Twitter? My handle is fkalseth. On LinkedIn? I`m there too.


Disclaimer

This is a personal blog; any opinions expressed here are my own and do not necessarily reflect those of my employer. All content herein is my own original creation, and as such is protected by copyright law. Unless otherwise stated, all source code posted on this blog is freely usable under the Microsoft Permissive License.

What Readers Talk About

Comment RSS