winform控件大小改变是防止背景重绘导致的闪烁


在工作中需要做一个伸缩控件,这个自定义控件继承于Panel。这个伸缩控件分为两个部分,头部是一个自定义组件,伸缩控件的背景为灰色,头部背景要求白色。伸缩控件在点击按钮时会重绘,同时他内部的控件也会重绘,这样就导致伸缩时界面会闪烁。

设置双缓存不能满足要求。

有一个解决方案的思路是使得某个控件的绘制背景图方法(OnPaintBackground方法)直接放回,不调用基类的该方法,同时重写绘制方法(OnPaint方法)用图片一次性绘制到背景。要求设置背景图片。

/// 
/// 加强版 Panel
/// 
class PanelEnhanced : Panel
{
    /// 
    /// OnPaintBackground 事件
    /// 
    /// 
    protected override void OnPaintBackground(PaintEventArgs e)
    {
        // 重载基类的背景擦除函数,
        // 解决窗口刷新,放大,图像闪烁
        return;
    }

    /// 
    /// OnPaint 事件
    /// 
    /// 
    protected override void OnPaint(PaintEventArgs e)
    {
        // 使用双缓冲
        this.DoubleBuffered = true;
        // 背景重绘移动到此
        if (this.BackgroundImage != null)
        {
            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            e.Graphics.DrawImage(
                this.BackgroundImage,
                new System.Drawing.Rectangle(0, 0, this.Width, this.Height),
                0,
                0,
                this.BackgroundImage.Width,
                this.BackgroundImage.Height,
                System.Drawing.GraphicsUnit.Pixel);
        }
        base.OnPaint(e);
    }
}

基于这个思路,如果控件的背景是纯色,可以自己绘制一个位图作为背景图片,进行填充。

     protected override void OnPaintBackground(PaintEventArgs e)
        {
            // 基类的方法不能用, 防止点击伸缩时重绘背景导致闪烁
            return;
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            /* 创建一个白色背景的位图作为背景,防止点击伸缩时重绘背景导致闪烁。
             * 不可在初始化的时候绘制该背景位图,
             * 因为容器自适应于父控件的长宽,初始化时候的长宽不一定是最终长宽。
             * 所以每次触发绘制方法的时候都要重新读取控件的长宽以便重绘位图
             */
            Bitmap bmp = new Bitmap(this.Width, this.Height);
            using (Graphics graph = Graphics.FromImage(bmp))
            {
                Rectangle ImageSize = new Rectangle(0, 0, this.Width, this.Height);
                graph.FillRectangle(Brushes.White, ImageSize);
            }

            e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
            e.Graphics.DrawImage(bmp, new System.Drawing.Rectangle(0, 0, this.Width, this.Height),
                0, 0, this.Width, this.Height,
                System.Drawing.GraphicsUnit.Pixel);

            ////基类的OnPaint方法不能使用,防止点击伸缩时重绘背景导致闪烁
            //base.OnPaint(e);
        }