How can I make the cursor turn to the wait cursor?

C#.NetWinformsUser InterfaceMouse Cursor

C# Problem Overview


How can I display the Wait/Busy Cursor (usually the hourglass) to the user to let them know the program is doing something?

C# Solutions


Solution 1 - C#

You can use Cursor.Current.

// Set cursor as hourglass
Cursor.Current = Cursors.WaitCursor;

// Execute your time-intensive hashing code here...

// Set cursor as default arrow
Cursor.Current = Cursors.Default;

However, if the hashing operation is really lengthy (MSDN defines this as more than 2-7 seconds), you should probably use a visual feedback indicator other than the cursor to notify the user of the progress. For a more in-depth set of guidelines, see this article.

Edit:
As @Am pointed out, you may need to call Application.DoEvents(); after Cursor.Current = Cursors.WaitCursor; to ensure that the hourglass is actually displayed.

Solution 2 - C#

Actually,

Cursor.Current = Cursors.WaitCursor;

temporarily sets the Wait cursor, but doesn’t ensure that the Wait cursor shows until the end of your operation. Other programs or controls within your program can easily reset the cursor back to the default arrow as in fact happens when you move mouse while operation is still running.

A much better way to show the Wait cursor is to set the UseWaitCursor property in a form to true:

form.UseWaitCursor = true;

This will display wait cursor for all controls on the form until you set this property to false. If you want wait cursor to be shown on Application level you should use:

Application.UseWaitCursor = true;

Solution 3 - C#

Building on the previous, my preferred approach (since this is a frequently performed action) is to wrap the wait cursor code in an IDisposable helper class so it can be used with using() (one line of code), take optional parameters, run the code within, then clean up (restore cursor) afterwards.

public class CursorWait : IDisposable
{
    public CursorWait(bool appStarting = false, bool applicationCursor = false)
    {
        // Wait
        Cursor.Current = appStarting ? Cursors.AppStarting : Cursors.WaitCursor;
        if (applicationCursor) Application.UseWaitCursor = true;
    }

    public void Dispose()
    {
        // Reset
        Cursor.Current = Cursors.Default;
        Application.UseWaitCursor = false;
    }
}

Usage:

using (new CursorWait())
{
    // Perform some code that shows cursor
}

Solution 4 - C#

It is easier to use UseWaitCursor at the Form or Window level. A typical use case can look like below:

    private void button1_Click(object sender, EventArgs e)
    {

        try
        {
            this.Enabled = false;//optional, better target a panel or specific controls
            this.UseWaitCursor = true;//from the Form/Window instance
            Application.DoEvents();//messages pumped to update controls
            //execute a lengthy blocking operation here, 
            //bla bla ....
        }
        finally
        {
            this.Enabled = true;//optional
            this.UseWaitCursor = false;
        }
    }

For a better UI experience you should use Asynchrony from a different thread.

Solution 5 - C#

My approach would be to make all the calculations in a background worker.

Then change the cursor like this:

this.Cursor = Cursors.Wait;

And in the thread's finish event restore the cursor:

this.Cursor = Cursors.Default;

Note, this can also be done for specific controls, so the cursor will be the hourglass only when the mouse is above them.

Solution 6 - C#

OK so I created a static async method. That disabled the control that launches the action and changes the application cursor. It runs the action as a task and waits for to finish. Control returns to the caller while it waits. So the application remains responsive, even while the busy icon spins.

async public static void LengthyOperation(Control control, Action action)
{
    try
    {
        control.Enabled = false;
        Application.UseWaitCursor = true;
        Task doWork = new Task(() => action(), TaskCreationOptions.LongRunning);
        Log.Info("Task Start");
        doWork.Start();
        Log.Info("Before Await");
        await doWork;
        Log.Info("After await");
    }
    finally
    {
        Log.Info("Finally");
        Application.UseWaitCursor = false;
        control.Enabled = true;
    }

Here's the code form the main form

    private void btnSleep_Click(object sender, EventArgs e)
    {
        var control = sender as Control;
        if (control != null)
        {
            Log.Info("Launching lengthy operation...");
            CursorWait.LengthyOperation(control, () => DummyAction());
            Log.Info("...Lengthy operation launched.");
        }

    }

    private void DummyAction()
    {
        try
        {
            var _log = NLog.LogManager.GetLogger("TmpLogger");
            _log.Info("Action - Sleep");
            TimeSpan sleep = new TimeSpan(0, 0, 16);
            Thread.Sleep(sleep);
            _log.Info("Action - Wakeup");
        }
        finally
        {
        }
    }

I had to use a separate logger for the dummy action (I am using Nlog) and my main logger is writing to the UI (a rich text box). I wasn't able to get the busy cursor show only when over a particular container on the form (but I didn't try very hard.) All controls have a UseWaitCursor property, but it doesn't seem have any effect on the controls I tried (maybe because they weren't on top?)

Here's the main log, which shows things happening in the order we expect:

16:51:33.1064 Launching lengthy operation...
16:51:33.1215 Task Start
16:51:33.1215 Before Await
16:51:33.1215 ...Lengthy operation launched.
16:51:49.1276 After await
16:51:49.1537 Finally

Solution 7 - C#

Okey,Other people's view are very clear, but I would like to do some added, as follow:

Cursor tempCursor = Cursor.Current;
        
Cursor.Current = Cursors.WaitCursor;

//do Time-consuming Operations         

Cursor.Current = tempCursor;

Solution 8 - C#

For Windows Forms applications an optional disabling of a UI-Control can be very useful. So my suggestion looks like this:

public class AppWaitCursor : IDisposable
{
	private readonly Control _eventControl;

	public AppWaitCursor(object eventSender = null)
	{
		 _eventControl = eventSender as Control;
		if (_eventControl != null)
			_eventControl.Enabled = false;

		Application.UseWaitCursor = true;
		Application.DoEvents();
	}

	public void Dispose()
	{
		if (_eventControl != null)
			_eventControl.Enabled = true;

		Cursor.Current = Cursors.Default;
		Application.UseWaitCursor = false;
	}
}

Usage:

private void UiControl_Click(object sender, EventArgs e)
{
	using (new AppWaitCursor(sender))
	{
		LongRunningCall();
	}
}

Solution 9 - C#

With the class below you can make the suggestion of Donut "exception safe".

using (new CursorHandler())
{
    // Execute your time-intensive hashing code here...
}

the class CursorHandler

public class CursorHandler
    : IDisposable
{
    public CursorHandler(Cursor cursor = null)
    {
        _saved = Cursor.Current;
        Cursor.Current = cursor ?? Cursors.WaitCursor;
    }

    public void Dispose()
    {
        if (_saved != null)
        {
            Cursor.Current = _saved;
            _saved = null;
        }
    }

    private Cursor _saved;
}

Solution 10 - C#

Use this with WPF:

Cursor = Cursors.Wait;

// Your Heavy work here

Cursor = Cursors.Arrow;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMalfistView Question on Stackoverflow
Solution 1 - C#DonutView Answer on Stackoverflow
Solution 2 - C#draganstankovicView Answer on Stackoverflow
Solution 3 - C#mhappsView Answer on Stackoverflow
Solution 4 - C#dmihailescuView Answer on Stackoverflow
Solution 5 - C#AmirshkView Answer on Stackoverflow
Solution 6 - C#Darrel LeeView Answer on Stackoverflow
Solution 7 - C#wenhaView Answer on Stackoverflow
Solution 8 - C#HEFView Answer on Stackoverflow
Solution 9 - C#GeorgView Answer on Stackoverflow
Solution 10 - C#Abdulrazzaq AlzayedView Answer on Stackoverflow