Dual ListBox Buffer

I have a CheckedListBox (WinForms) control (which inherits from a ListBox, googling shows that the problem is with the ListBox), which is tied to all four sides of its form. When the form size changes, the ListBox has an ugly flicker. I tried to inherit CheckedListBox and set DoubleBuffered to true in ctor (this method works with other controls, including ListView and DataGridView), but it had no effect.

I tried adding the WS_EX_COMPOSITED style to WS_EX_COMPOSITED , and this helped, but reduces the size of the form less.

Is there any other way to prevent this flicker?

+7
c # winforms listbox doublebuffered
source share
4 answers

I had similar problems, although listbox handles the owner. My solution was to use BufferedGraphics objects. Your mileage may vary depending on this decision if your list is not drawn by the owner, but perhaps this will give you some inspiration.

I found that the TextRenderer is having difficulty rendering to the correct location unless I send TextFormatFlags.PreserveGraphicsTranslateTransform. An alternative to this was to use P / Invoke to invoke BitBlt to directly copy pixels between graphic contexts. I chose this as the lesser of two evils.

 /// <summary> /// This class is a double-buffered ListBox for owner drawing. /// The double-buffering is accomplished by creating a custom, /// off-screen buffer during painting. /// </summary> public sealed class DoubleBufferedListBox : ListBox { #region Method Overrides /// <summary> /// Override OnTemplateListDrawItem to supply an off-screen buffer to event /// handlers. /// </summary> protected override void OnDrawItem(DrawItemEventArgs e) { BufferedGraphicsContext currentContext = BufferedGraphicsManager.Current; Rectangle newBounds = new Rectangle(0, 0, e.Bounds.Width, e.Bounds.Height); using (BufferedGraphics bufferedGraphics = currentContext.Allocate(e.Graphics, newBounds)) { DrawItemEventArgs newArgs = new DrawItemEventArgs( bufferedGraphics.Graphics, e.Font, newBounds, e.Index, e.State, e.ForeColor, e.BackColor); // Supply the real OnTemplateListDrawItem with the off-screen graphics context base.OnDrawItem(newArgs); // Wrapper around BitBlt GDI.CopyGraphics(e.Graphics, e.Bounds, bufferedGraphics.Graphics, new Point(0, 0)); } } #endregion } 

GDI class (proposed by frenchtoast ).

 public static class GDI { private const UInt32 SRCCOPY = 0x00CC0020; [DllImport("gdi32.dll", CallingConvention = CallingConvention.StdCall)] private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, UInt32 dwRop); public static void CopyGraphics(Graphics g, Rectangle bounds, Graphics bufferedGraphics, Point p) { IntPtr hdc1 = g.GetHdc(); IntPtr hdc2 = bufferedGraphics.GetHdc(); BitBlt(hdc1, bounds.X, bounds.Y, bounds.Width, bounds.Height, hdc2, pX, pY, SRCCOPY); g.ReleaseHdc(hdc1); bufferedGraphics.ReleaseHdc(hdc2); } } 
+11
source share

You can check if switching to a ListView control is improved with checkboxes. It's not that easy to handle (but hey, WinForms ListBox is not a genius either), I found that resizing with DoubleBuffered=true tolerable.

Alternatively, you can try to reduce flicker by overriding the background image of the parent forms - either by providing a hollow brush, or by redefining WM_ERASEBKND without doing anything and returning TRUE . (This is normal if your control covers the entire client area of ​​the parent form, otherwise you will need a more sophisticated background painting method.

I have successfully used this in Win32 applications, but I don't know if the Forms control adds its own magic, which makes it non-functional.

+2
source share

This was used to send the WM_SETREDRAW message to the control.

 const int WM_SETREDRAW = 0x0b; Message m = Message.Create(yourlistbox.Handle, WM_SETREDRAW, (IntPtr) 0, (IntPtr) 0); yourform.DefWndProc(ref m); // do your updating or whatever else causes the flicker Message m = Message.Create(yourlistbox.Handle, WM_SETREDRAW, (IntPtr) 1, (IntPtr) 0); yourform.DefWndProc(ref m); 

See also: WM_SETREDRAW Link in Microsoft Fixed Link

If anyone else used Windows messages in .NET, please update this publication as necessary.

0
source share

Although this does not apply to a specific flicker problem, a method that is often effective for this type of problem is to cache the minimum state of ListBox items. Then determine if you need to redraw the ListBox by doing some calculations for each item. Update the ListBox only if you need to update at least one item (and, of course, save this new state in the cache for the next cycle).

0
source share

All Articles