Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

A Simple Wait Window

4.50/5 (22 votes)
8 Mar 2010CPOL4 min read 1   15.4K  
Showing a wait window during a long running process

Introduction

Back in the days when I used FoxPro, we would always pop up a wait window while running any long process. Come .NET, there is no built in wait window, so you have to roll your own. This has become an increasing issue as we issue calls to web services that may be fast or slow. In the mean time, our users need to know the application has not crashed. They should also not be able to click on any other part of the application until the process has finished, in the same manner as the old FoxPro wait window.

waitwindow.png

Background

There are a few details that need to be covered for a good wait window.

During our process, we want to provide an animation on the wait window to ensure the user believes the application has not crashed. For the purposes of this article, I have used a ProgessBar, but you could equally use an animated GIF, or some custom animation scheme of your own devising. The side effect is that the worker method must execute on a secondary thread or it will block the GUI updating the animation.

Also, we cannot use a BackgroundWorker for this as we want the execution to occur inline. For example, we want to call the wait window specifying the method to execute, then expect it to have finished by the time we hit the next line of code. Therefore we will have to roll our own threading code.

Using the Code

I have built the sample code with the wait window in a separate assembly so you can just reference the assembly if you want. However, I expect most people will copy the classes into their own project structure, which is fine.

Before anyone asks, the sample code includes the project in C# and in VB.NET, and while I have compiled it against the 3.5 framework, it should be fine built against any .NET Framework version, though you would have to manually copy the code into a Visual Studio 2005 project if you wanted to use the older solution format.

First, you will need to write your method to execute. Remember this is running on a separate thread, so pass everything in and return the results, or ensure any calls you make are guaranteed thread safe!

To make things easier, the event args for the method include a collection of arguments that you can pass in, and a reference to the WaitWindow object so that the message displayed can be updated during the process. The code below shows most of the things you may want to do. For more examples, see the demo project.

C#
private void WorkerMethod(object sender, Jacksonsoft.WaitWindowEventArgs e){
	// Do something
	for (int progress = 1; progress <= 100; progress++){
		System.Threading.Thread.Sleep(20);
		
		// Update the wait window message
		e.Window.Message = string.Format
		("Please wait ... {0}%", progress.ToString().PadLeft(3));
	}
	
	// Use the arguments sent in
	if (e.Arguments.Count> 0){
		// Set the result to return
		e.Result = e.Arguments[0].ToString();
	} else {
		// Set the result to return
		e.Result = "Hello World";
	}
}

Next, you need to call the WaitWindow with the method you have created. The example below just uses the default, "Please wait..." message, but you can also pass in the message to display, and any arguments for the worker method. Again, there are more examples in the demo project.

C#
object result = WaitWindow.Show(this.WorkerMethod);

There are two methods exposed by the WaitWindow object that can be called from within the worker method. These are the methods, Cancel() and the property, Message. These cancel the execution immediately, and update the message displayed in the WaitWindow respectively.

Points of Interest

In the first release, I did some clever stuff to make a modeless window appear modal, however it was pointed out that I did not actually need this at all.

If you do want to do this for some other reason, you have to capture the mouse and then capture all the windows messages and ensure that only the ones you want get passed on to the rest of the application.

We pass the Form into the AddMessageFilter method to hook up the form to receive all the windows messages first.

C#
System.Windows.Forms.Application.AddMessageFilter(this._GUI);

Inside the code for the window, we can now implement the IMessageFilter interface giving us a PreFilterMessage method. All that remains is to return true for the mouse and keyboard events, rather than the default false and the window will now act as if it were modeless when in fact it is modal.

A shame that I ditched that rather neat piece of code because it was a pointless waste of time, but that's development for you, a constant learning process. 

History

  • First release - March 2010
  • Release 2 - Updated for simpler threading model (Many thanks to John Brett for his input)
  • Release 3 - Updated to support cancellation and better exception handling

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)