Double buffered ListBox

前端 未结 4 1445
轻奢々
轻奢々 2021-02-15 11:16

I have a CheckedListBox (WinForms) control (which inherits from ListBox; googling shows that the problem is with ListBox) that is anchored to all four sides of its form. When t

4条回答
  •  感情败类
    2021-02-15 11:30

    I was having similar issues albeit with an owner drawn listbox. My solution was to use BufferedGraphics objects. Your mileage may vary with this solution if your list isn't owner drawn, but maybe it will give you some inspiration.

    I found that TextRenderer had difficulties rendering to the correct location unless I suppled TextFormatFlags.PreserveGraphicsTranslateTransform. The alternative to this was to use P/Invoke to call BitBlt to directly copy pixels between the graphics contexts. I chose this as the lesser of two evils.

    /// 
    /// This class is a double-buffered ListBox for owner drawing.
    /// The double-buffering is accomplished by creating a custom,
    /// off-screen buffer during painting.
    /// 
    public sealed class DoubleBufferedListBox : ListBox
    {
        #region Method Overrides
        /// 
        /// Override OnTemplateListDrawItem to supply an off-screen buffer to event
        /// handlers.
        /// 
        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
    }
    

    The GDI class (suggested 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, p.X, p.Y, SRCCOPY);
    
            g.ReleaseHdc(hdc1);
            bufferedGraphics.ReleaseHdc(hdc2);
        }
    }
    

提交回复
热议问题