Raymond Chen just finished a short series on LockWindowUpdate, including when to use it and when not to. I enjoy reading Raymond’s blog for a number of reasons. His posts are short, to the point, and well written, and he discusses topics that I, as a .NET developer who is younger (read: showed up after most of the Win32 GUI programming days were long past) am not aware of. In this case, he had a great impact on me as in a few places I’ve been very much misusing LockWindowUpdate. I needed to stop a control from drawing over the course of several operations, to prevent flicker, etc.
After reading his series (which I encourage you to do), I went back and created a class I called ControlRedrawLock which can be used to, well, lock redrawing of a control.
One word of caution, however. I couldn’t believe something like this hadn’t been included as a method on Control, so I did some reflectorin’ to look around. Control.BeginUpdateInternal and Control.EndUpdateInternal do exactly what I was looking for, including ref counting and everything. But sure enough, as are many useful things, they are marked as internal. On the other hand, I could see that if these were exposed publicly on all controls it could be a potential source of some confusing bugs. A few select controls do expose this (such as ComboBox), probably just where it makes sense. The word of warning, then, is to be very careful in your use of this class. You might get undesirable results if you combine it’s usage with parts of controls that internally call EndUpdateInternal as my class will re-enable drawing regardless of what’s going on. That said, enjoy!
Here’s how you would use it:
using (new ControlRedrawLock(this)) { // Do something }
And here’s the code:
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; namespace Lerch.UI { public class ControlRedrawLock : IDisposable { [DllImport(“user32.dll”, EntryPoint=“SendMessage”)] public static extern int SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam); public static int WM_SETREDRAW = 0×000B; private Control _control; private bool _invalidate; private bool _disabledRedraw = false; public ControlRedrawLock(Control control) : this(control, true) { } public ControlRedrawLock(Control control, bool invalidate) { try { _control = control; _invalidate = invalidate; if (IsValidControl()) { // Lock drawing SendMessage(_control.Handle, WM_SETREDRAW, 0, 0); _disabledRedraw = true; } } catch { } } private bool IsValidControl() { return ((_control != null) && (_control.IsHandleCreated)); } #region IDisposable Members public void Dispose() { try { if (IsValidControl() && _disabledRedraw) { // Unlock drawing SendMessage(_control.Handle, WM_SETREDRAW, 1, 0); if (_invalidate) { // Invalidate the control to trigger a re-paint. _control.Invalidate(true); } } } catch { } } #endregion } }


Leave a comment