我有一个CheckedListBox(WinForms)控件(它继承自ListBox;谷歌搜索表明问题出在ListBox上),该控件固定在其窗体的所有四个方面。调整窗体的大小时,列表框闪烁起来很丑。我尝试继承CheckedListBox并将ctor中的DoubleBuffered设置为true(此技术可与其他控件一起使用,包括ListView和DataGridView),但没有效果。

我尝试将 WS_EX_COMPOSITED 样式添加到CreateParams中,这有所帮助,但使窗体调整大小时的糊糊速度更慢。

还有其他方法可以防止这种闪烁吗?

最佳答案

我有一个类似的问题,尽管拥有者绘制了列表框。我的解决方案是使用BufferedGraphics对象。如果您的 list 不是所有者绘制的,则此解决方案的里程数可能会有所不同,但这也许会给您一些启发。

我发现TextRenderer很难渲染到正确的位置,除非我添加了TextFormatFlags.PreserveGraphicsTranslateTransform。替代方法是使用P/Invoke调用BitBlt在图形上下文之间直接复制像素。我选择这作为两个邪恶中的较小者。

/// <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类(由 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);
    }
}

关于c# - 双缓冲ListBox,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1131912/

10-11 02:04