【问题标题】:Custom combobox control border flickers when mouse hovers in and out鼠标悬停进出时自定义组合框控件边框闪烁
【发布时间】:2017-03-14 10:20:11
【问题描述】:

我正在开发一个源自标准组合框的自定义组合框控件,根据此处的文章,该控件看起来扁平且无边框:

http://www.codeproject.com/Articles/6971/Making-Standard-ComboBox-appear-flat

根据各种来源,我必须重写 windows 过程才能做到这一点,所以这是我的 WndProc 重写,我在其中阻止了几条消息到达控件:

protected override void WndProc(ref Message m)
{
    IntPtr hDC = IntPtr.Zero;
    Graphics gdc = null;

    switch (m.Msg)
    {
        // Block these messages
        case WM_CHANGEUISTATE:
        case WM_MOUSEACTIVATE:
        case WM_MOUSEFIRST:
        case WM_MOUSELAST:
        case WM_MOUSEHOVER:
        case WM_MOUSELEAVE:
            m.Result = (IntPtr)1;
            break;

        // Here we paint the border when non-client paint is received
        case WM_NC_PAINT:
            hDC = GetWindowDC(this.Handle);
            gdc = Graphics.FromHdc(hDC);
            SendMessage(this.Handle, WM_ERASEBKGND, hDC, 0);
            SendPrintClientMsg();   // Send to draw client area
            PaintFlatControlBorder(this, gdc);
            m.Result = (IntPtr) 1;  // Indicate message has been processed          
            ReleaseDC(m.HWnd, hDC);
            gdc.Dispose();
            break;

        case WM_PAINT:
            base.WndProc(ref m);
            // Flatten the border area again
            hDC = GetWindowDC(this.Handle);
            gdc = Graphics.FromHdc(hDC);
            Pen p = new Pen((this.Enabled? BackColor:SystemColors.Control), 2);
            gdc.DrawRectangle(p, new Rectangle(2, 2, this.Width-3, this.Height-3));
            PaintFlatDropDown(this, gdc);
            PaintFlatControlBorder(this, gdc);
            ReleaseDC(m.HWnd, hDC);
            gdc.Dispose();
            break;

            default:
                base.WndProc(ref m);
                break;
    }
}

这是我的构造函数:

public FlatComboBox() : base()
{
    this.FlatStyle = FlatStyle.Flat;
    this.SetStyle(ControlStyles.DoubleBuffer | ControlStyles.ResizeRedraw, true);
}

我还需要阻止哪些其他 wndproc 消息,或者有其他方法可以解决这个问题吗?

这里是所有 wndproc 消息的一个很好的参考:

https://www.autoitscript.com/autoit3/docs/appendix/WinMsgCodes.htm

我正在使用 .NET v4.5。

提前致谢。

【问题讨论】:

    标签: c# winforms combobox controls winforms-interop


    【解决方案1】:

    我之前使用组合框完成此操作,为其提供可自定义的平面外观,我展示了完整代码以便更容易了解它的工作原理,但是它使用自定义下拉菜单和菜单项完成外观。

    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    
    namespace Custom.Controls
    {
        public class CustomComboBox : UserControl
        {
            private const int DEFAULT_WIDTH = 121;
            private const int DEFAULT_HEIGHT = 20;
    
            private CustomContextMenuStrip _popupControl;
            private CustomToolStripMenuItem _selectedItem;
            private bool _bDroppedDown;
    
            private Color _borderColour;
            private Color _dropDownButtonColour;
            private Color _droppedDownArrowColour;
            private Color _closedArrowColour;
    
            private Color _dropDownBackColour;
            private Color _dropDownForeColour;
            private Color _dropDownBorderColour;
    
            public Color BorderColour
            {
                get
                {
                    return _borderColour;
                }
                set
                {
                    _borderColour = value;
    
                    this.Invalidate();
                }
            }
    
            public Color ClosedArrowColour
            {
                get
                {
                    return _closedArrowColour;
                }
                set
                {
                    _closedArrowColour = value;
    
                    this.Invalidate();
                }
            }
    
            public Color DroppedDownArrowColour
            {
                get
                {
                    return _droppedDownArrowColour;
                }
                set
                {
                    _droppedDownArrowColour = value;
    
                    this.Invalidate();
                }
            }
    
            public Color DropDownButtonColour
            {
                get
                {
                    return _dropDownButtonColour;
                }
                set
                {
                    _dropDownButtonColour = value;
    
                    this.Invalidate();
                }
            }
    
            public Color DropDownBorderColour
            {
                get
                {
                    return _dropDownBorderColour;
                }
                set
                {
                    _dropDownBorderColour = value;
    
                    _popupControl.BorderColour = value;
    
                    this.Invalidate();
                }
            }
    
            public Color DropDownBackColour
            {
                get
                {
                    return _dropDownBackColour;
                }
                set
                {
                    _dropDownBackColour = value;
    
                    _popupControl.BackColor = value;
    
                    this.Invalidate();
                }
            }
    
            public Color DropDownForeColour
            {
                get
                {
                    return _dropDownForeColour;
                }
                set
                {
                    _dropDownForeColour = value;
    
                    _popupControl.ForeColor = value;
    
                    this.Invalidate();
                }
            }
    
            public bool DropShadowEnabled
            {
                get
                {
                    return _popupControl.DropShadowEnabled;
                }
                set
                {
                    _popupControl.DropShadowEnabled = value;
    
                    this.Invalidate();
                }
            }
    
            public bool DroppedDown
            {
                get
                {
                    return _bDroppedDown;
                }
                set
                {
                    _bDroppedDown = value;
    
                    if (value)
                    {
                        _popupControl.Show(this, new Point(0, this.Height), ToolStripDropDownDirection.BelowRight);
                    }
                    else
                    {
                        _popupControl.Hide();
                    }
    
                    this.Invalidate();
                }
            }
    
            public ToolStripItemCollection Items
            {
                get
                {
                    return _popupControl.Items;
                }
            }
    
            public CustomToolStripMenuItem SelectedItem
            {
                get
                {
                    return _selectedItem;
                }
            }
    
            public CustomComboBox()
            {
                this.SetStyle(ControlStyles.ResizeRedraw, true);
                this.SetStyle(ControlStyles.Selectable, true);
                this.SetStyle(ControlStyles.UserMouse, true);
                this.SetStyle(ControlStyles.UserPaint, true);
    
                this.SuspendLayout();
                this.ResumeLayout(false);
    
                _popupControl = new CustomContextMenuStrip();
                _popupControl.BackColor = this.BackColor;
                _popupControl.Closed += new ToolStripDropDownClosedEventHandler(PopupControl_Closed);
                _popupControl.ItemClicked += new ToolStripItemClickedEventHandler(PopupControl_ItemClicked);
    
                this.Width = DEFAULT_WIDTH;
                this.Height = DEFAULT_HEIGHT;
    
                _selectedItem = null;
                _bDroppedDown = false;
    
                this.BackColor = SystemColors.Control;
                this.ForeColor = SystemColors.ControlText;
    
                _borderColour = SystemColors.ActiveBorder;
                _dropDownButtonColour = SystemColors.ButtonFace;
                _droppedDownArrowColour = SystemColors.ControlLight;
                _closedArrowColour = SystemColors.ControlDark;
    
                //Set these via the properties so they take effect on _popupControl
                this.DropDownBackColour = SystemColors.Control;
                this.DropDownForeColour = SystemColors.ControlText;
                this.DropDownBorderColour = SystemColors.ActiveBorder;
            }
    
            protected override void OnFontChanged(EventArgs e)
            {
                _popupControl.Font = this.Font;
    
                base.OnFontChanged(e);
            }
    
            protected override void OnMouseDown(MouseEventArgs e)
            {
                this.Invalidate();
    
                this.DroppedDown = !this.DroppedDown;
    
                base.OnMouseDown(e);
            }
    
            protected override void OnMouseWheel(MouseEventArgs e)
            {
                int nIndex = this.Items.IndexOf(_selectedItem);
                if (e.Delta < 0)
                {
                    if (nIndex < (this.Items.Count - 1))
                    {
                        _selectedItem = (CustomToolStripMenuItem)this.Items[nIndex + 1];
    
                        OnSelectedItemChanged(EventArgs.Empty);
                        this.Invalidate();
                    }
                }
                else if (e.Delta > 0)
                {
                    if (nIndex > 0)
                    {
                        _selectedItem = (CustomToolStripMenuItem)this.Items[nIndex - 1];
    
                        OnSelectedItemChanged(EventArgs.Empty);
                        this.Invalidate();
                    }
                }
    
                base.OnMouseWheel(e);
            }
    
            protected override void OnPaint(PaintEventArgs e)
            {
                Rectangle boundingRect = new Rectangle(0, 0, this.Width, this.Height);
    
                using (SolidBrush brush = new SolidBrush(this.BackColor))
                {
                    e.Graphics.FillRectangle(brush, boundingRect);
                }
                ControlPaint.DrawBorder(e.Graphics, boundingRect, _borderColour, ButtonBorderStyle.Solid);
    
                //Draw the dropdown button background
                int nButtonWidth = SystemInformation.VerticalScrollBarWidth + SystemInformation.VerticalFocusThickness;
                Rectangle dropDownButtonRect = new Rectangle(this.Width - nButtonWidth, 0, nButtonWidth, this.Height);
                using (SolidBrush brush = new SolidBrush(_dropDownButtonColour))
                {
                    e.Graphics.FillRectangle(brush, dropDownButtonRect);
                }
    
                //Draw the dropdown button arrow
                using (GraphicsPath path = new GraphicsPath())
                {
                    Point pTopLeft = new Point()
                    {
                        X = (int)Math.Round((float)dropDownButtonRect.X + ((float)dropDownButtonRect.Width * 0.30f)),
                        Y = (int)Math.Round((float)dropDownButtonRect.Y + ((float)dropDownButtonRect.Height * 0.35f))
                    };
    
                    Point pTopRight = new Point()
                    {
                        X = (int)Math.Round((float)dropDownButtonRect.X + ((float)dropDownButtonRect.Width * 0.70f)),
                        Y = (int)Math.Round((float)dropDownButtonRect.Y + ((float)dropDownButtonRect.Height * 0.35f))
                    };
    
                    Point pBottom = new Point()
                    {
                        X = (int)Math.Round((float)dropDownButtonRect.X + ((float)dropDownButtonRect.Width * 0.5f)),
                        Y = (int)Math.Round((float)dropDownButtonRect.Y + ((float)dropDownButtonRect.Height * 0.65f))
                    };
    
                    path.AddLine(pTopLeft, pTopRight);
                    path.AddLine(pTopRight, pBottom);
    
                    SmoothingMode previousSmoothingMode = e.Graphics.SmoothingMode;
                    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                    {
                        using (SolidBrush brush = new SolidBrush(_bDroppedDown ? _droppedDownArrowColour : _closedArrowColour))
                        {
                            e.Graphics.FillPath(brush, path);
                        }
                    }
                    e.Graphics.SmoothingMode = previousSmoothingMode;
                }
    
                if (_selectedItem != null)
                {
                    using (SolidBrush brush = new SolidBrush(this.ForeColor))
                    {
                        SizeF stringSize = e.Graphics.MeasureString(_selectedItem.Text, this.Font);
                        e.Graphics.DrawString(_selectedItem.Text, this.Font, brush, new Point(0, (this.Height / 2) - ((int)stringSize.Height / 2)));
                    }
                }
            }
    
            protected override void OnSizeChanged(EventArgs e)
            {
                if (_popupControl != null)
                {
                    _popupControl.MaximumItemSize = new Size(this.Width - 1, _popupControl.MaximumItemSize.Height);
                    _popupControl.Width = this.Width;
                }
    
                base.OnSizeChanged(e);
            }
    
            private void OnSelectedItemChanged(EventArgs e)
            {
                if (SelectedItemChanged != null)
                {
                    SelectedItemChanged(this, e);
                }
            }
    
            public void SelectFirstItem()
            {
                if (this.Items != null && this.Items.Count > 0)
                {
                    _selectedItem = (CustomToolStripMenuItem)this.Items[0];
    
                    OnSelectedItemChanged(EventArgs.Empty);
                }
            }
    
            public event EventHandler SelectedItemChanged;
    
            private void PopupControl_Closed(object sender, ToolStripDropDownClosedEventArgs e)
            {
                this.DroppedDown = false;
    
                this.Invalidate(true);
            }
    
            private void PopupControl_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
            {
                _selectedItem = (CustomToolStripMenuItem)e.ClickedItem;
    
                OnSelectedItemChanged(EventArgs.Empty);
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-29
      • 2011-09-01
      • 2021-10-08
      • 2014-10-21
      • 1970-01-01
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      相关资源
      最近更新 更多