Introduction

Making your WinForm applications User Friendly is important. One aspect of a good user experience is informing your user that your application is unresponsive during short periods of work. This article introduces an effective and simple way of adding application wide WaitCursors using one line of start-up code.

Background

Recently, I have been working on a WinForms project at home that occasionally performs some short (less than 5 seconds) running tasks. I wanted the user to be informed that during that short period the UI is unresponsive, so I chose to use the Cursors.WaitCursor to indicate this. This article shows how I came to my final WaitCursor library implementation which I believe is a completely re-usable library.

Using the code

From a developer's point of view, using the WaitCursor library could not get any simpler. Add a reference to the WaitCursor assembly and then add the following line to your application start-up code:

ApplicationWaitCursor.Cursor = Cursors.WaitCursor;

That’s it!

You can of course use any Cursor you like, you can use one of the predefined Cursors or you can create a new cursor and use that instead. You can also fine tune the amount of work time that will elapse before the Cursor is shown:

Now that’s better, I've guaranteed that the Cursor will always be returned to the Default cursor even if an exception occurs. However, I found it arduous to wrap that code around every short running task that I was developing.

Then I remembered how I used to use C++ stack based destructors to perform tear down work upon exiting of a method:

void DoShortRunningTask()
{
StWaitCursor cursor = new StWaitCursor();
.. do some work ..
// Implicitly called ~StWaitCursor returns the Cursor to Default
}

But I couldn't use C# destructors the same way since you can't guarantee when a C# destructor is called since the Garbage Collector thread is responsible for that.

Instead, C# uses a different language feature, the using statement which implicitly calls the Dispose method of objects that implement IDisposable. Although (I find it's) not quite as easy to use as the C++ destructor, you can achieve the same result with the using statement:

There, nice and simple. I found, however, that if my short running task was too short then the user sees a quick flickering of the Cursor to and from the WaitCursor, quite annoying. So I decided I needed a way of turning the WaitCursor on after a predefined amount of time during a task.

After quite a few iterations and refactorings, I came up with what I called the StDelayedCallback class (see source code) which is a generic class that once instantiated will wait for a specified amount of time before calling the Start method of an IDelayedCallbackHandler, and ifStart was called that it was guaranteed to call the Finish method of the same interface. Once I had this, I could easily implement the interface such that the WaitCursor was turned on when Start was called and returned the Default cursor when Finish was called.

Some things I found

During development of the WaitCursor library, I discovered that I could not set Cursor.Current on any thread other than the GUI thread. This is where the Win32 AttachThreadInput method can be used to get around this problem effectively. So I developed the StThreadAttachedDelayedCallback class which wraps up the call to the AttachThreadInput.

So eventually I ended up with a generic StDelayedCallback class, a ThreadInput attached version of it called StThreadAttachedDelayedCallback and a specific Cursor implementation called StWaitCursor. Incidentally, I used the prefix St since I had originally intended on using these classes in a similar way to the C++ Stack based classes I had used in the past. So up until now, I had intended on using the following:

However, it still meant I had to be explicit about where I wanted my WaitCursor to show.

Then I had an attack of brilliance and came up with the ApplicationWaitCursor singleton class which neatly wraps the StWaitCursor such that whenever the application is working, or rather, whenever it’s not regularly calling OnApplicationIdle, then the StWaitCursor kicks in and shows the WaitCursor.

The only caveat I found was when I dragged a window around which blocks the OnApplicationIdle call. So, I also intercept the WM_NCLBUTTONDOWN message (which is sent at the beginning of the window dragging) to temporarily disable the StWaitCursor.

That's where I am up to with the current WaitCursor implementation and in brief how I got there. You can easily derive from the StDelayedCallback class to create similar effects. Perhaps you would like to show an Indefinite progress bar during your long running tasks, or indicate "Saving Changes..." in a StatusBar control:

privatevoid SaveChanges()
{
using (new StStatusBar(stbMain, "Saving Changes...")
{
.. do some work ..
}
// StStatusBar.IDispose could return the Text
// of the StatusBar to its original value
}

Note that the source code does not contain the StStatusBar class, I am just using it as an example of other ways you could use the StDelayedCallback class.

History

Version 1.0.0.0 (12th March 2005)

Initial version.

Version 1.0.1.0 (16th March 2005)

Updated to be CLS compliant (thanks to C a r l and Mathew Hall for pointing this out).

How can i prevent the cursors from going to waitcursor when I call up the standard copy paste dialog ?
Select text in a text box, press right mouse key, The copy past dialog appears. 2 seconds in the dialog the cursor turns to waitcursor. Any ideas ?
The dialog is not mine but standard.

Thanks for the Code, it's just what I was looking for. But i'm noticing a few other bugs that noone has mentioned.

The main one is that when you start typing in a textbox, the cursor disappears. Moving the mouse or tabbing to the next control brings it back.
[interesting side note: it doesn't happen if you are only Backspacing the text in the textbox]

Also, a very small bug. If you are using a DateTimePicker and either:
a. click the calendar drop-down button and don't move the mouse
or b. use F4 to open the calendar
Then the WaitCursor will appear until the mouse is moved or the calendar is closed.

I don't expect you to fix these, I just wanted to add them to the bug list.

Testing for a few minutes, the hourglass cursor also appears:
1) When scrolling through a long datagridview
2) When you press (and don't release) the mouse button on a treeview item
3) Once you start drag operation
4) A few times it appeared when scrolling through a multiline textbox, but I was unable to reproduce it coherently

Although I appreciate the concern and effort put into this utility, I don't think it's really ready for primetime until these issues are dealt with. Good luck with fixing them, tho.

I'm back here downloading your code to include in a home project. I saw my earlier post below - nearly three years ago now I was here saying how brilliant this was, and it still is!

We've been using your automatic application wait cursor at work in our rich client apps for nearly three years and have had no problems at all. In htat time I have been working for a large UK government organisation with a team of about 10 developers shipping custom apps to various "business units". Your code has given us no problems at all in that time and has saved us a load of work.

I've linked to this library in .Net v2.0, v3.0, and v3.5 projects. I've also opened and compiled the project in Visual Studio 2005 & 2008. If I recall correctly, it was a VS2003 project file and needed to be upgraded for both VS 2005 & 2008 and both worked perfectly.

After testing a while I'm still excited about your solution.
I only encountered 1 minor fault.
When I push a scroll bar and slide, then the wait timer is shown.
I tried using prefilteredmessages, but when I disable the leftdown, then the wait cursor is never shown on a left mouse down.
Have yo uencountered this problem?
For now I will keep the waitcursor when scrolled, because everuthing works normally, only they get to see a waitcursor when scrolling.
I tried setting the timeout to 1 sec, but scrolling can take up to a few seconds, so that didn't helped either.
Greetz...

In tight loops that effect how the GUI is displayed it is typical to call Application.DoEvents(); so that the GUI has some time to repaint. Otherwise the GUI appears to be completely locked up and you get strange paint artifacts. When I simulate this in your test project the WaitCursor turns off at the first DoEvents, and never turns back on.

Hi Sean, I think you missed the point, there is already a (configurable) delay before the wait cursor appears. The reason why it flashes when you increase your sleep time is that the wait cursor delay expires during the Sleep and the WaitCursor appears which is then turned off again during the DoEvents.

I try really hard not to use DoEvents() since it can cause stack overflow issues if not done cautiously. Any real intensive work that you want to the user to see some progress on should be done on a seperate thread with asynchronous Invokes back to the GUI thread for UI updates only.

The WaitCursor is meant for really short delays where 1 or 2 seconds of unresponsiveness is not too harsh for the user. Form_Loads are a good example, particularly on control rich Forms and slower machines, during a Form_Load the user cannot do anything anyway, so informing them of a slight delay via the wait cursor is neat.

It's 1:00 am and I've just finished sweeping the app prototype that I'm going to show to customers tomorrow, wanted to add in some wait cursors and came across your automatic version. It just works and has saved me adding any code to my app at all.

Man, I just wanted to say 'thanks' for making that available - much appreciated

I have one question though. I have a contextmenu thats being drawn dynamically when the user hits Shift + F5. The popup comes up fine; but, the hour glass keeps on showing after the context menu has been shown.

Not that I have tried it yet but Andy Baker (another post) has enhanced the Wait Cursor quite smartly such that it does not depend on the Application Idle event which is not posted during mouse operations.

I have no current plans to develop the StStatusBar class, I just used it as an example of other applications the technique could have, although I dont see StStatusBar as being overly complicated.

Firstly the hour glass stays on when you show right click content menus (including built in content menus). This can be fixed by checking for the right button down + content menu messages in your message callback.

Secondly (depending on how busy the application is) the hour glass will sometimes stay on indefinitely (due to the order in which the application idle event fires).

Finally, it also continuously sets and unsets the cursor even when the application is idle - this seems unnecessary.

Anyway, still a good post. I have coded a revised version to this that takes a different approach and seems to work well (so far!). See below for the alternative:

This is quite simple.
Guess we have some method that is called asynchronously and synchronously.
At synchronous way it works fine asynchronously it doesn't work. When you move the mouse you can see that the cursor is not consistent.

If you will locate two buttons on a form and bind them to the buttons events you will look what I'm talking about.
Button 1 click will open work on another thread in the process and in the mean time the cursor will not be consistent if you will move it over the form.

The idea of the Application WaitCursor is to show when the Main thread is busy. If you are performing work on other threads then the UI will be fully responsive and a wait cursor is probably not necessary.

Having said that and without having tried it, you should still be able to show the Wait Cursor on another thread using ..

using (new StWaitCursor())
{
DoWork();
}

You would generally perform short (<3 seconds) tasks on the Main thread and the Wait Cursor makes good sense. Any more than 3 or so seconds then you probably should use either a progress bar, or like you said use a seperate thread to perform the work in the background. If using a background thread you would probably want some way of informing the user of progress and perhaps the ability to cancel the operation aswell. This however is beyond what the Wait Cursor is intended for.

When I use your sample with a SandDock (http://www.divil.co.uk/net/)
I have a trouble when mouse pointer stop over a pinned window( like a Toolbox in VisualStudio).
Normally ( sithout your component) this window must be popped up. Your component disable this functionality.

Well Carl, for my uses I dont need any fixes currently. I can see (from other posts) that under some scenarios the cursor will show unexpectantly but you have the same source code that I do and you are quite welcome to make enhancements and fixes to suite your needs and if you feel generous enough you can email me your changes so I can post updates (with contributors thanked), this is after all a community of sharing.

As for your clients, and not to be rude, but I am not getting anything from them nor do I have any responsibility to them, they are your clients and your responsibilities. The source I posted comes with no warranties, I am sure it has potentially saved your at least a few hours of tedious coding, so for you to make a few fixes here and there won't harm.

--EDIT: I just found major problems implementing the proposed fix. I'll keep you posted.

--EDIT 2: The proposed fixes seem to work, except when filtering WM_LBUTTONUP. When I filter it, everything that is done upon leftclicking a button (pretty much everything is started by a left click!), the application wait cursor doesn't show up. So here are the fixes that I added to ApplicationWaitCursor.cs: