Click here to Skip to main content
15,889,861 members
Articles / Programming Languages / C#
Tip/Trick

Repainting WinForms windows safely inside a processing loop (safe DoEvents)

Rate me:
Please Sign up or sign in to vote.
5.00/5 (4 votes)
21 Dec 2012CPOL1 min read 30.1K   607   7   6
This example illustrates the correct use of Application.DoEvents() in order to allow a window to repaint (or handle the desired messages) while its thread is busy doing heavy processing.

Introduction

This example illustrates the correct use of Application.DoEvents() in order to allow a window to repaint (or handle the desired messages) while its thread is busy doing heavy processing.

Background

Calling Application.DoEvents() used to be the easy way of making your window repaint, but this method is really dangerous, because it not only allows the window to repaint, but also processes all the events the user issues to the window, such as button presses etc., which can lead to unwanted behavior in the form of function reentrancy or unwanted event handler execution, leading to malfunction and possible crashes.

Using the code

The code comes in the form of a utility class with a function called DoPaintEvents().

The solution is based on the use of a IMessageFilter that decides which messages will do execution and which don’t, and it’s pretty straightforward and easy to modify to fit other user needs.

C#
namespace System.Windows.Forms
{
    /// <summary> System.Windows.Forms utilities </summary>
    public static class WinFormUtils
    {
       /// <summary> Processes all Paint events only </summary>
       public static void DoPaintEvents()
       {
           //MessageFilter registration
           Application.AddMessageFilter(PaintMessageFilter.Instance);
           //Process messages in the queue
           Application.DoEvents();
           //MessageFilter desregistration
           Application.RemoveMessageFilter(PaintMessageFilter.Instance);
       }
 
       /// <summary> Custom message filter </summary>
       private class PaintMessageFilter : IMessageFilter
       {
           static public IMessageFilter Instance = new PaintMessageFilter();
 
           #region IMessageFilter Members
 
           /// <summary> Message filter function </summary>
           public bool PreFilterMessage(ref System.Windows.Forms.Message m)
           {
                   return (m.Msg != 0x000F); //WM_PAINT -> we only let WM_PAINT messages through
           }
 
           #endregion
       }
    }
}

Now, if you walk into a processing loop inside a button click message handler you will be able to call WinFormUtils.DoPaintEvents() in order to make your window repaint itself safely.

C#
private void button1_Click(object sender, EventArgs e)
{
   bool done = false;
   while(!done) //This loop will leave your window stuck
   {
        //Process something
        done = DoSomeHeavyStuff();
        //Repaint the window
        WinFormUtils. DoPaintEvents ();
   }
}

Points of Interest

You can modify the PreFilterMessageFunction in order to let any message you need through, like min/max/restore events, for instance.

History

No changes yet.

License

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


Written By
Software Developer (Senior)
Spain Spain
Programming since the times of good old Spectrum.
Windows developer (from C++/COM to C# now).

Comments and Discussions

 
QuestionAre messages discarded? Pin
Ádám Juhász14-Jan-22 4:42
Ádám Juhász14-Jan-22 4:42 
AnswerRe: Are messages discarded? Pin
dromanol14-Jan-22 10:32
dromanol14-Jan-22 10:32 
Questionstill dangerous Pin
VV1215214712-May-16 4:11
VV1215214712-May-16 4:11 
I used and liked your implementation to force painting. It took me a couple of days to find out that this is responsible for some strange behaviors in our software. A WinForms button stayed pushed while mouse is released. WPF controls are not painted if properties changed. Now I know that important messages like MouseUp and WPF registrations was swallowed by this DoPaint implementation.

Application.DoEvents without message filter is dangerous because you don't know what you do. Application.DoEvents with message filter is dangerous because you don't know what you miss to do.
AnswerRe: still dangerous Pin
dromanol12-May-16 4:46
dromanol12-May-16 4:46 
GeneralDangerous Pin
Maxence Delannoy28-Dec-13 21:57
Maxence Delannoy28-Dec-13 21:57 
GeneralRe: Dangerous Pin
dromanol1-Jan-14 20:23
dromanol1-Jan-14 20:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.