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.
namespace System.Windows.Forms
{
public static class WinFormUtils
{
public static void DoPaintEvents()
{
Application.AddMessageFilter(PaintMessageFilter.Instance);
Application.DoEvents();
Application.RemoveMessageFilter(PaintMessageFilter.Instance);
}
private class PaintMessageFilter : IMessageFilter
{
static public IMessageFilter Instance = new PaintMessageFilter();
#region IMessageFilter Members
public bool PreFilterMessage(ref System.Windows.Forms.Message m)
{
return (m.Msg != 0x000F); }
#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.
private void button1_Click(object sender, EventArgs e)
{
bool done = false;
while(!done) {
done = DoSomeHeavyStuff();
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.