在Windows窗体中覆盖WM_PAINT时出现闪烁问题

时间:2014-10-14 23:52:34

标签: c# combobox custom-controls

我想这是一般性问题,并不仅限于ComboBox,但我对ComboBox有特殊的问题。我用MyCB扩展了ComboBox对象MyCB : ComboBox

每当我将鼠标悬停在控件上,离开控件,展开选择框或选择一个值时,控件就会闪烁。有一段时间我可以看到默认(未替换)控件,它会立即被我的替换。

我相信正在发生的事情是Windows首先绘制“原始”控件(通过调用base.WndProc()),然后重新绘制它。

问题是,我可以以某种方式阻止窗户绘制它自己的控制并立即绘制我的吗?

以下是覆盖WndProc

的代码
protected override void WndProc(ref Message m)
{       
    base.WndProc(ref m);

    if (m.Msg == WM_PAINT)
    {
        Graphics gg = this.CreateGraphics();
        gg.FillRectangle(BorderBrush, this.ClientRectangle);

        // ... //

        //Draw the arrow
        gg.FillPath(ArrowBrush, pth);

        // ... //

        if(this.Text == "")
            gg.DrawString("-- SELECT --", this.Font, new SolidBrush(Color.Black), rf, sf);
        else
            gg.DrawString(this.Text, this.Font, new SolidBrush(Color.Black), rf, sf);

        gg.Dispose();
    }
}

到目前为止我尝试了什么:

  • 我知道我不能这样做:

    if (m.Msg == WM_PAINT)
    {
        ...
    }
    else
    {
        base.WndProc(ref m);
    }
    

    因为这将导致控制无限地重绘自己(不确定原因)

  • 我能够通过添加此代码来消除鼠标离开/进入控件时发生的闪烁

    if (m.Msg == WM_MOUSEFIRST || m.Msg == WM_MOUSELEAVE) // 0x0200 0x02A3
    {
        m.Result = (IntPtr)1;
    }
    else
    {
        base.WndProc(ref m);
    
        if (m.Msg == WM_PAINT)
        {
            ...
        }
    }
    

    然而,这并没有完全解决问题

  • 我查看了ILSpy以查看ComboBox的WndProc但是有太多的窗口消息,我不知道哪些我可能想要实现我的目标

1 个答案:

答案 0 :(得分:0)

    public CustomComboBox()
    {
        SetStyle(ControlStyles.DoubleBuffer, true);
        SetStyle(ControlStyles.ResizeRedraw, true);
        SetStyle(ControlStyles.SupportsTransparentBackColor, true);
    }

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == Win32.WM_MOUSEFIRST || m.Msg == Win32.WM_MOUSELEAVE || m.Msg == Win32.WM_MOUSEHOVER) //0x0200, 0x02A3, 0x02A1
        {
            m.Result = (IntPtr)1;
            return;
        }

        base.WndProc(ref m);
        if (m.Msg == Win32.WM_PAINT)
        {
            IntPtr hDC = Win32.GetWindowDC(m.HWnd);
            Graphics g = Graphics.FromHdc(hDC);

            g.SmoothingMode = SmoothingMode.HighSpeed;
            g.PixelOffsetMode = PixelOffsetMode.HighSpeed;
            g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
            if (Text.Length == 0)
            {
                StringFormat stringFormat = new StringFormat
                {
                    Alignment = StringAlignment.Near,
                    LineAlignment = StringAlignment.Near
                };
                g.DrawString("Water Marks", Font, new SolidBrush(Color.FromArgb(51, 51, 51)), (Bounds.Width - 2), FontHeight + 2, stringFormat);
            }

            Pen border = new Pen(ui_BorderLineColor, 1);
            g.DrawRectangle(border, 0, 0, this.Width - 1, this.Height - 1);

            g.Dispose();
            Win32.ReleaseDC(m.HWnd, hDC);

        }
    }

    protected override void InitLayout()
    {
        base.InitLayout();
        DropDownStyle = ComboBoxStyle.DropDownList; //Works only in DropDownList          
    }