Console Application Wait/Busy Spin Animation

Introduction

If you would like your console application to show a spinning animation (cycle through characters | / - \ in place) to show your application is busy/working, then the following class can do that for you.

Simple run the animation using.

SpinAnimation.Start() or SpinAnimation.Start(50) depending on how fast you want your animation to spin.

To stop the animation use.

SpinAnimation.Stop()

Spin animation will deliberately throw an invalid operation when attempting to start it twice but can be checked with the Boolean ISBusyproperty prior to starting. Stop can be called twice successively without any exceptions.

Here is the class, which is self-documented to describe how it works.

/// <summary>
/// Create spinning console busy animation running on a background thread
/// </summary>
public static class SpinAnimation
{
    // Spinner background thread
    private static System.ComponentModel.BackgroundWorker spinner = InitialiseBackgroundWorker();

    // Starting position of spinner changes to current position on start
    private static int spinnerPosition = 25;

    // Pause time in milliseconds between each character in the spin animation
    private static int spinWait = 25;

    // Field and property to inform client if spinner is currently running
    private static bool isRunning;

    public static bool IsRunning => isRunning;

    /// <summary>
    /// Worker thread factory
    /// </summary>
    /// <returns>Background worker thread</returns>
    private static System.ComponentModel.BackgroundWorker InitialiseBackgroundWorker()
    {
        var obj = new System.ComponentModel.BackgroundWorker();

        // Allow cancellation to be able to stop the spinner
        obj.WorkerSupportsCancellation = true;

        // Anonymous method for background thread's DoWork event
        obj.DoWork += delegate
        {
            // Set the spinner position to the current console position
            spinnerPosition = Console.CursorLeft;

            // Run animation unless a cancellation is pending
            while (!obj.CancellationPending)
            {
                // Characters to iterate through during animation
                char[] spinChars = { '|', '/', '-', '\\' };

                // Iterate through the animation character array
                foreach (char spinChar in spinChars)
                {
                    // Reset the cursor position to the spinner position
                    Console.CursorLeft = spinnerPosition;

                    // Write the current character to the console
                    Console.Write(spinChar);

                    // Pause for smooth animation - set by the Start method
                    System.Threading.Thread.Sleep(spinWait);
                }
            }
        };

        return obj;
    }

    /// <summary>
    /// Start the animation
    /// </summary>
    /// <param name="spinWait">Wait time between spin steps in milliseconds</param>
    public static void Start(int spinWait)
    {
        // Set the running flag
        isRunning = true;

        // Process spinWait value
        SpinAnimation.spinWait = spinWait;

        // Start the animation unless already started
        if (!spinner.IsBusy)
            spinner.RunWorkerAsync();
        else
            throw new InvalidOperationException("Cannot start spinner whilst spinner is already running");
    }

    /// <summary>
    /// Overloaded Start method with default wait value
    /// </summary>
    public static void Start()
    {
        Start(25);
    }

    /// <summary>
    /// Stop the spin animation
    /// </summary>
    public static void Stop()
    {
        // Stop the animation
        spinner.CancelAsync();

        // Wait for cancellation to complete
        while (spinner.IsBusy)
            System.Threading.Thread.Sleep(100);

        // Reset the cursor position
        Console.CursorLeft = spinnerPosition;

        // Set the running flag
        isRunning = false;
    }
}


Similar Articles