Jelle Druyts .NET Consultant
Just another ignorant weirdo from Antwerp, Belgium trying to make sense out of it all
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...
null
/// <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(); } }