C# Wait Cursor that automatically goes away

I actually did a post around this topic a while ago on another site that is now defunct, but I figured it is still useful, and I have a few additional details to add.

Back in the C++/MFC days, there was a cute trick you could do in order to have a wait cursor appear while an operation was in progress, and then automatically go away. All you had to do was to create an appropriate object at the top of your method:

BOOL SomeMethod()
{
  CWaitCursor wait; 

  // Do stuff 
}

Because the wait object went out of scope at the end of the method, it could automatically restore the cursor to its old state.

You can’t do quite the same thing in C#, but you can come close–via the use of the Dispose pattern and a using statement. The code would look like this:

public void SomeMethod()
{
  using(new WaitCursor())
  {
    // Do stuff
  }
}

The using statement works with objects that implement the IDisposable interface, and is really just a shortcut. Effectively, behind the scenes, the code above will be converted into code that looks more-or-less like this:

IDisposable o = new WaitCursor();
try
{
  // Do stuff
}
finally
{
  o.Dispose();
}

This is the same pattern that it used for things like files – the Dispose() method in that case would close the file. You generally want to have files closed and resources released as soon as possible, rather than waiting for the garbage collector to get around to it at its leisure. Likewise, we want the wait cursor to show up while you are doing things, but then immediately go away.

WinForms version

There is no built-in WaitCursor class in .NET, but the code is very simple. Here is the WinForms version (comments and error checks omitted for space):

using System;
using System.Windows.Forms;

public class WaitCursor : IDisposable
{
  private m_oldCursor = null;

  public WaitCursor()
  {
    m_oldCursor = Cursor.Current;
    Cursor.Current = Cursors.WaitCursor;
  }

  public void Dispose()
  {
    Cursor.Current = m_oldCursor;
  }
}

You can now put a using(new WaitCursor()) around any code that might take a bit of time so that the user won’t try to overclick. One very common situation where it makes sense to do this is when you are bringing up dialogs:

using(new WaitCursor())
{
  using(MyDialog dlg = new MyDialog())
  {
    dlg.ShowDialog();
  }
}

You might think that this would be bad – that the wait cursor will be stuck in front of your dialog while it is being displayed, but that won’t happen at all. The wait cursor will be displayed while your dialog is being initialized, but as soon as it is actually shown, all of the processing happens in a different message loop (which processes things like drawing, clicks, etc.), and that message loop will do its own cursor handling. The wait cursor will reappear as the dialog is going away (when processing is passed back to the main message loop) and then will go away again when the code leaves the using block.

BTW – Note that I put a using statement around the dialog as well – this is a good practice, since it means that resources used by the dialog will be cleaned up immediately.

Although the using(new WaitCursor()) syntax is a little bit more verbose than just declaring an object at the top of your method, I actually have come to prefer it since you have more control (and more visibility) over the cursor’s lifetime.

WPF Version

If you are using WPF, you can do more-or-less exactly the same thing, although the code for the WaitCursor class is a bit different:

using System;
using System.Windows.Input;

public class WpfWaitCursor : IDisposable
{
  private Cursor m_oldCursor = null;

  public WpfWaitCursor()
  {
    m_oldCursor = Mouse.OverrideCursor;
    Mouse.OverrideCursor = Cursors.Wait
  }

  public void Dispose()
  {
    Mouse.OverrideCursor = m_oldCursor;
  }
}

As you can see, very similar. Although the mechanics are a little different, you can also use the WPF version around modal dialogs as well.

Longer operations

If you are doing something that may take a few moments, then showing a wait cursor is a really good idea–even if on your machine the operation is fairly fast (users might have slower machines or slower network connections, etc.). However, if you are doing anything that will take a substantial amount of time, then a wait cursor by itself is probably not going to cut it, since your UI will be locked. Eventually, Windows will show a “not responding” message in the title bar, and the user may give up on your application.

In those scenarios, you need to do work in the background and give feedback to the user. That used to be a little complicated, but since C# and .NET added really good asynchronous support, it is now quite easy. That is the topic of a future post.

Tagged with: , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *

*