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

479,863

Solution 1

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

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

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

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

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.

Share:
479,863

Related videos on Youtube

Programatt
Author by

Programatt

I am a programmer by day, and a tinkerer by night.

Updated on December 23, 2021

Comments

  • Programatt
    Programatt over 2 years

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

  • Amirshk
    Amirshk over 14 years
    this won't necessary change the cursor - if the message loop won't be called during the time-intensive code. to enable it you need to add Application.DoEvents(); after the first cursor set.
  • Amirshk
    Amirshk over 14 years
    @Malfist: good approach :), then all you need to do is place the restore in the end event, and your done.
  • TrueWill
    TrueWill over 14 years
    You probably want a try..finally block after setting Current, too (insuring that Current gets reset to Default).
  • Hans Rudel
    Hans Rudel almost 12 years
    FYI, i couldnt get the above to work, but by changing it to this.cursor = cursors.waitcursor; it worked.
  • itsho
    itsho almost 11 years
    Good to know. I was trying to do the same in WPF, and ended up with Cursor = Cursors.Wait and Cursor = Cursors.Arrow. But I couldn't find the Cursor under App
  • Vbp
    Vbp over 10 years
    Hourglass was not displayed if I used Application.DoEvents() after Cursor.Current = Cursors.WaitCursor However, it did worked without Application.DoEvents() . Not sure Why
  • Bron Davies
    Bron Davies about 10 years
    Run your time intensive operations on a background Thread like this: ThreadStart ts = new ThreadStart(DoSomethingLong); Thread t = new Thread(ts); t.Start();
  • Chandra Eskay
    Chandra Eskay over 9 years
    Couldn't find UseWaitCursor under Application !
  • John Henckel
    John Henckel almost 9 years
    This should be the ACCEPTED answer. It is the only one that uses try-finally.
  • torno
    torno over 8 years
  • mhapps
    mhapps over 8 years
    Hadn't seen that, but yes similar approach. He backs up the current cursor then restores it, which may be useful if you're doing heavy cursor changing.
  • Jack
    Jack almost 8 years
    have my upvote, I was missing a try-finally in my implementation
  • Gianpiero
    Gianpiero over 7 years
    It is better to use Application.UseWaitCursor = true and Application.UseWaitCursor = false
  • Danny Mahoney
    Danny Mahoney over 7 years
    @GianpieroCaretti Why is that? Please explain.
  • Stewart
    Stewart over 6 years
    I found that, when setting form.UseWaitCursor = false at the end of the operation, it doesn't actually reset the cursor until you move or click the mouse. OTOH, form.Cursor doesn't have this problem. I couldn't get Cursor.Current to work at all.
  • AlirezaK
    AlirezaK over 6 years
    @GianpieroCaretti, in all solutions that came above, only your solution worked for me.
  • Eric Wood
    Eric Wood over 3 years
    I like your answer but I would suggest placing it in the context of a try / finally. I used Donut's accepted answer for years, but it does not work in code behind on a C# .NET Core 3.1 WPF application like your answer. With the ,NET Core, Microsoft has changed the interface and objects in regards to cursors.
  • Epic Speedy
    Epic Speedy about 3 years
    Definitely use this if you want to use the wait cursor. I tried Cursor.Current but it kept being reset instantly for some reason, this solution makes the waiting cursor persist until changed to false.
  • Fabio Pagano
    Fabio Pagano about 3 years
    @GianpieroCaretti The solution is ok, anyway a "doevents" (after the instruction) is needed also in this case.
  • Sid133
    Sid133 almost 3 years
    This is the clean solution if we need a responsive UI as well as inform something is running.
  • Dan Randolph
    Dan Randolph about 2 years
    But what do you do if your 2 sec task is loading data into the control itself? (such as RichTextbox) I don't think using a background worker would help in this case, but I could be wrong.