In my last project for Windows Mobile, I’ve needed report progress of running operations. Well, there is no big deal about it but if you display message like Connecting or Locating it is kind of static. I was looking for something like Internet Explorer Mobile does. The little circle in the status panel circling while operations are running. Since I did not want to mess with some drawing or picture showing, I decided to use good old dots. Snake of five dots growing one by one and then disappears and then again. Exactly like on the picture.

Animated status panel 322x242

StatusPanel user control

Result of my effort is simple user control, which consist of Panel and Label. Beside the standard properties for visual appearance like Font, ForeColor etc.. There are the Text property for showing the text and Anime property for turning animation on and off. Animation is done by System.Threading.Timer which executes in regular intervals and increases count of the dots.

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
using System.Threading;

namespace AnimeStatus
{
    /// <summary>
    /// Implements status panel with animation capabilities
    /// </summary>
    public class StatusPanel : UserControl
    {
        #region Fields
        private Label statusLabel;        
        private Panel statusPanel;
        private System.Threading.Timer animationTimer;
        private int animationIndex;
        private bool animationStatus;
        private string statusText;
        #endregion

        public StatusPanel()
        {
            animationStatus = false;
            this.BorderStyle = BorderStyle.FixedSingle;

            // Status Panel 
            statusPanel = new Panel();
            statusPanel.Dock = DockStyle.Fill;
            statusPanel.BackColor = SystemColors.ScrollBar;

            // Status Label         
            statusLabel = new Label();
            statusLabel.Dock = DockStyle.Bottom;
            statusPanel.Controls.Add(statusLabel);            

            this.Controls.Add(statusPanel);
        }

        /// <summary>
        /// Start animation
        /// </summary>
        private void StartAnimation()
        {
            if (animationTimer == null)
            {
                animationIndex = 1;
                animationTimer = new System.Threading.Timer(new TimerCallback(OnAnimationTimer), null, 100, 500);
            }
        }

        /// <summary>
        /// Stop animation
        /// </summary>
        private void StopAnimation()
        {
            if (animationTimer != null)
            {
                animationTimer.Dispose();
                animationTimer = null;
                animationIndex = 0;
                UpdateAnimation(string.Empty);
            }
        }

        /// <summary>
        /// TimerCallback for animation
        /// </summary>
        /// <param name="status">null</param>
        private void OnAnimationTimer(object status)
        {            
            string animText = string.Empty;
            for (int i = 0; i < animationIndex; i++)
                animText += ".";

            UpdateAnimation(animText);

            animationIndex = (animationIndex < 5) ? ++animationIndex : 0;
        }

        /// <summary>
        /// Thread safe animation
        /// </summary>
        /// <param name="status">string with dots</param>
        private void UpdateAnimation(object status)
        {
            if (this.InvokeRequired)
            {
                this.BeginInvoke(new WaitCallback(UpdateAnimation), status);
                return;
            }

            statusLabel.Text = statusText+(string)status;            
        }
        
        /// <summary>
        /// Release all resources
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources</param>
        protected override void Dispose(bool disposing)
        {
            StopAnimation();
            base.Dispose(disposing);
        }

        #region Properties
        /// <summary>
        /// Turns animation on and off
        /// </summary>
        public bool Animate
        {
            get { return animationStatus; }
            set
            {
                animationStatus = value;

                if (animationStatus)
                    StartAnimation();
                else
                    StopAnimation();
            }
        }

        /// <summary>
        /// The text contained in the control
        /// </summary>
        public override string Text
        {
            get { return statusText; }
            set
            {
                statusLabel.Text = statusText = value;
                Application.DoEvents();
            }
        }

        /// <summary>
        /// The background color used to display text and graphics in the control.
        /// </summary>
        public override Color BackColor
        {
            get { return (statusPanel != null) ? statusPanel.BackColor : SystemColors.Window; }
            set { statusPanel.BackColor = value; }
        }

        /// <summary>
        /// The foreground color used to display text and graphics in the control.
        /// </summary>
        public override Color ForeColor
        {
            get { return (statusLabel != null) ? statusLabel.ForeColor : SystemColors.ControlText; }
            set { statusLabel.ForeColor = value; }
        }

        /// <summary>
        /// Font used to display text in the control.
        /// </summary>
        public override Font Font
        {
            get { return (statusLabel != null) ? statusLabel.Font : null; }
            set { statusLabel.Font = value; }
        }
        #endregion
    }
}

To show panel you can use following code snippet

animatedPanel = new StatusPanel();
animatedPanel.Height = 25;
animatedPanel.Dock = DockStyle.Bottom;
this.Controls.Add(animatedPanel);

animatedPanel.Animate = true;
animatedPanel.Text = "Counting";

Hiding is also very easy

this.Controls.Remove(animatedPanel);
animatedPanel.Dispose();