Cursors#

If you've ever written a client app with some time consuming code, you probably wanted to show the obligatory hourglass at some point. This is not a hard thing to do in .NET, but you should be careful to do it right.

One way would be to just do this (in some method of a form or control):

this.Cursor = Cursors.WaitCursor;
// time consuming code...
this.Cursor = Cursors.Default;

However, this can result in an hourglass that never goes away if your time consuming code decided to fail and bail out with an exception.

This looks better:

try
{
   this.Cursor = Cursors.WaitCursor;
   // time consuming code...
}
finally
{
   this.Cursor = Cursors.Default;
}

But this approach has one minor drawback: you can't stack operations on top of each other. If this code got called from some other time consuming code which had already set the hourglass, you're now falsely telling the user that it has already finished.

What you should do is remember the cursor as it is before you're changing it, and restoring it at the end. This can get pretty boring copy/paste code if you need to do this a lot so I wrote a little helper class which wraps this up for you. Your code can now be as elegant as:

using( new CursorHelper( this ) )
{
   // time consuming code...
}

Here's the code for the helper class. It just remembers the current state, and restores it when disposed. You can also use an overloaded constructor to use other cursors than the hourglass by the way. It could use some more defensive code (like checking if the control isn't null or already disposed etc.) but it gives you a good idea...

/// <summary>
/// A helper object that allows to set and restore the cursor on a control easily.
/// </summary>
/// <example>
/// This will create a WaitCursor on a control and restore it to the previous state after the "using" block:
/// <code>
///   using( new CursorHelper( this ) )
///   {
///      // time consuming code...
///   }
/// </code>
/// </example>
public class CursorHelper : IDisposable
{
   /// <summary>
   /// The previous cursor of the associated control.
   /// </summary>
   private Cursor m_OldCursor;
   /// <summary>
   /// The control of which to set the cursor.
   /// </summary>
   private Control m_Control;
   /// <summary>
   /// Creates a new CursorHelper for the given control. Sets the current cursor to
   /// a WaitCursor and restores the previous cursor on Dispose or destruction.
   /// </summary>
   /// <param name="ctrl">The control of which to set the cursor.</param>
   public CursorHelper( Control ctrl )
   {
      m_OldCursor = ctrl.Cursor;
      m_Control = ctrl;
      ctrl.Cursor = Cursors.WaitCursor;
   }
   /// <summary>
   /// Creates a new CursorHelper for the given control. Sets the current cursor to
   /// the given cursor and restores the previous cursor on Dispose or destruction.
   /// </summary>
   /// <param name="ctrl">The control of which to set the cursor.</param>
   /// <param name="newCursor">The new cursor to set.</param>
   public CursorHelper( Control ctrl, Cursor newCursor )
   {
      m_OldCursor = ctrl.Cursor;
      m_Control = ctrl;
      ctrl.Cursor = newCursor;
   }
   /// <summary>
   /// Restores the cursor on the associated control.
   /// </summary>
   public void Dispose()
   {
      m_Control.Cursor = m_OldCursor;
      GC.SuppressFinalize( this );
   }
   /// <summary>
   /// Restores the cursor on the associated control.
   /// </summary>
   ~CursorHelper()
   {
      Dispose();
   }
}
Thursday, November 13, 2003 5:44:48 PM (Romance Standard Time, UTC+01:00)
You should take your object off the finalization queue when Disposed is called explicitly by calling GC.SuppressFinalize(this);
Peter
Saturday, November 15, 2003 6:42:38 PM (Romance Standard Time, UTC+01:00)
You're right, that's a small bug :-) I hacked this up pretty quickly so I'm sorry if it's breaking your production apps, but it's there now :-D
Jelle
Saturday, April 21, 2007 6:02:34 PM (Romance Standard Time, UTC+01:00)
very good
Comments are closed.
All content © 2008, Jelle Druyts
On this page

Recent Photos
www.flickr.com
This is a Flickr badge showing public photos from Jelle Druyts. Make your own badge here.
Advertising
Top Picks
Statistics
Total Posts: 344
This Year: 7
This Month: 0
This Week: 0
Comments: 522
Archives
Sitemap
Disclaimer
This is my personal website, not my boss', not my mother's, and certainly not the pope's. My personal opinions may be irrelevant, inaccurate, boring or even plain wrong, I'm sorry if that makes you feel uncomfortable. But then again, you don't have to read them, I just hope you'll find something interesting here now and then. I'll certainly do my best. But if you don't like it, go read the pope's blog. I'm sure it's fascinating.

Powered by:
newtelligence dasBlog 2.0.7226.0

Sign In