.NET Windows.Forms applications have a nasty habit of creating a lot of form flicker when doing form stuff like opening dialogs. This generally occurs when you have a long running operation (and I mean longer than a second) before opening a new form. This usually takes the shape of database access while retrieving values to display in your new dialog. Aside from that, there also isn't an easy built in way in Windows.Forms to show a wait cursor for the entire application while loading data.

The side effect of the flickering experienced by users is that your application appears to be slower than it actually is. It looks like your application hangs for a second or two to most users. I've even had users tell me that they can tell that the application is a .NET application because of the constant window flicker!

Clearly this kind of stigma is not something you want associated with your applications, so we'll explore a solution that not only takes care of the irritating flicker, but provides a reliable wait cursor across all forms in your application while you're busy loading data or doing other work.

The Hourglass class

Solving the wait cursor issue is easy thanks to a contribution by nobugz on the Microsoft Forums. Add the following class to your application:

    public class HourGlass : IDisposable {
        public HourGlass() {
            Enabled = true;
        }
        public void Dispose() {
            Enabled = false;
        }
        public static bool Enabled {
            get { return Application.UseWaitCursor; }
            set {
                if (value == Application.UseWaitCursor) return;
                Application.UseWaitCursor = value;
                Form f = Form.ActiveForm;
                if (f != null && f.Handle != null)   // Send WM_SETCURSOR
                    SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1);
            }
        }
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    }

 

Using the HourGlass class is a breeze, all you have to do is wrap any time consuming code in a new HourGlass as follows:

        private void btnOk_Click(object sender, EventArgs e) {
            using (new HourGlass()) { 
                // do some work here
            }
        }

And that's all there is to having a wait cursor apply to your entire application while your main thread is busy working.

Solving the flickering

Thanks to the HourGlass class, solving the flicker becomes a breeze too. The flicker happens because your long running work occurs on the main application thread before your forms have had a chance to process their paint messages. This causes the form painting to be delayed until after your long running work has completed. This results in half painted forms being visible to the user, especially when doing something like closing a dialog box.

The solution is to force the form to process it's paint messages before starting your long running work. You can do this easily by calling this.Update() on the form that you're working in, but the discipline required to remember to do so can be an issue.

Luckily for us, the HourGlass class has given us a perfect opportunity to automate this call! See the updated hourglass class below:

    public class HourGlass : IDisposable {
        public HourGlass() {
            Enabled = true;
        }
        public void Dispose() {
            Enabled = false;
        }
        public static bool Enabled {
            get { return Application.UseWaitCursor; }
            set {
                if (value == Application.UseWaitCursor) return;
                Application.UseWaitCursor = value;
                Form f = Form.ActiveForm;
                if (f != null && f.Handle != null) {   
                    // force the form to process it's paint messages
                    // before performing any long running work
                    f.Update();
                    // Send WM_SETCURSOR
                    SendMessage(f.Handle, 0x20, f.Handle, (IntPtr)1);
                }
            }
        }
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    }

We've inserted a call to Update() before sending the cursor message to the active form. This causes the active form to paint itself completely before changing cursors and before your long running work starts.

And there you go, suddenly your .NET Windows Forms application behaves just like every other well written Windows application!


I am a software developer / architect currently interested in combining .NET technologies with open-source operating systems. 

I am a member of the open-source BlogEngine.NET development team and focus mainly on ensuring Mono compatibility for the project.

twitter

BlogEngine.NET


At StayUnlimited Cape Town accommodation we help you choose from and book guest houses, self catering apartments, bed & breakfasts, luxury villas and hotel accommodation.