如何使用ControlPaint.DrawBorder方法修改ComboBox的边框颜色?

How can I use the ControlPaint.DrawBorder method to modifiy the border color of a ComboBox?

我有一个需求,需要设置Combobox控件的边框颜色。
我在 Google 中搜索了实现 ControlPaint.Drawborder.
的示例代码 我发现的并不理想。边框颜色未修改。
在下面的代码中,您将看到两个关键函数,WndProcPaintControlBorder(),它们用于接收底层 windows 事件并处理它们。
后者用于绘制控件的边框。用Visual Studio调试后,发现执行了PaintControlBorder()函数中的代码。

为什么边框颜色没有变化?

[ToolboxItem(true)]
public class ModifiedComboBox : ComboBox
{
    new public System.Windows.Forms.DrawMode DrawMode { get; set; }
    public Color HighlightColor { get; set; } //set select item highlight color 
    private IntPtr hDC;
    private Graphics gdc;
    private const int WM_ERASEBKGND = 0x14; // some windows message id 
    private const int WM_PAINT = 0xF;
    private const int WM_NC_PAINT = 0x85;
    private const int WM_PRINTCLIENT = 0x318;
    private const int WM_MOUSEHOVER = 0x2A1;
    private const int WM_MOUSELEAVE = 0x2A3;

    [DllImport("user32")]
    private static extern IntPtr GetDC(IntPtr hWnd);
    private Rectangle rectale;

    public ModifiedComboBox()
    {
        hDC = GetDC(Handle);
        gdc = Graphics.FromHdc(hDC);
        SetStyle(ControlStyles.Selectable, false);
        base.DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed;
        this.HighlightColor = Color.Gray;
        this.DrawItem += new DrawItemEventHandler(AdvancedComboBox_DrawItem); //t bind draw item handler

        rectale = new Rectangle(0, 0, Width, Height);
    }

    public void AdvancedComboBox_DrawItem(object sender, DrawItemEventArgs e)
    {
        if (e.Index < 0)
            return;

        ComboBox combo = sender as ComboBox;
        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        {
            e.Graphics.FillRectangle(new SolidBrush(HighlightColor), e.Bounds);
            //e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font, new SolidBrush(combo.BackColor), new Point(e.Bounds.X, e.Bounds.Y));

            e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font, new SolidBrush(combo.ForeColor), new Point(e.Bounds.X, e.Bounds.Y));
        }
        else
        {
            e.Graphics.FillRectangle(new SolidBrush(combo.BackColor), e.Bounds);
            e.Graphics.DrawString(combo.Items[e.Index].ToString(), e.Font, new SolidBrush(combo.ForeColor), new Point(e.Bounds.X, e.Bounds.Y));
        }
        e.DrawFocusRectangle();
    }

    protected override void WndProc(ref Message m)// windows message handler
    {
        if (this.DropDownStyle == ComboBoxStyle.Simple)
        {
            base.WndProc(ref m);
            return;
        }

        switch (m.Msg)
        {
            case WM_NC_PAINT:
                break;
            case WM_PAINT:
                base.WndProc(ref m);

                PaintControlBorder();
                break;
            default:
                base.WndProc(ref m);
                break;
        }
    }
    private void PaintControlBorder()
    {
            ControlPaint.DrawBorder(gdc, this.ClientRectangle, Color.Orange, ButtonBorderStyle.Solid);
    }
}

在 Windows 窗体中,您永远不会存储控件的图形对象。
您可以使用其中一种图形方法(Paint、DrawItem 等)提供的方法,或者像本例一样,在需要时创建一个新方法,然后立即处理它。
在此示例中,隐式地将 Graphics 对象创建包含在 using 块中。

这是一个简单的例子,使用ControlPaint.DrawBorder, that show how draw a border around a ComboBox control, using a Graphics object derived from the control Handle (Graphics.FromHwnd(this.Handle)) on a WM_PAINT message received overriding the control's WndProc

示例自定义控件公开了一个 public 属性、BorderColor,它允许更改边框的颜色。

using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Windows.Forms;

[DesignerCategory("Code")]
class ComboSimpleBorder : ComboBox
{
    private const int WM_PAINT = 0xF;
    private Color m_BorderColor = Color.Red;

    public ComboSimpleBorder() { }

    [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [EditorBrowsable(EditorBrowsableState.Always), Category("Appearance")]
    [Description("Get or Set the Color of the Control's border")]
    public Color BorderColor 
    {
        get => this.m_BorderColor;
        set { this.m_BorderColor = value; this.Invalidate(); }
    }

    [SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
    protected override void WndProc(ref Message m) {
        base.WndProc(ref m);
        if (m.Msg == WM_PAINT) {
            using (Graphics g = Graphics.FromHwnd(this.Handle)) {
                ControlPaint.DrawBorder(g, this.ClientRectangle, this.m_BorderColor, ButtonBorderStyle.Solid);
            }
            m.Result = IntPtr.Zero;
        }
    }
}