You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在.NET WinForms C#中移除ComboBox下拉列表蓝色焦点边框?

移除WinForms自定义ComboBox下拉列表的蓝色焦点边框

问题说明

自定义CxFlatComboBoxEnhanced控件时,下拉列表始终存在蓝色焦点边框。尝试通过处理0x0134(WM_CTLCOLORLISTBOX)消息移除边框,但仅在列表项获得焦点时生效;打开列表、鼠标移出窗体时边框重现,且代码会覆盖其他列表项。

问题根源

  1. DrawItem事件中调用e.DrawBackground()会触发系统绘制默认的焦点边框,无法完全自定义控制。
  2. 原0x0134消息处理逻辑错误:直接填充整个下拉区域会覆盖其他列表项,且没有正确拦截系统绘制焦点边框的流程。
  3. GDI资源(如SolidBrush)未正确释放,存在泄漏风险;且错误释放了系统提供的e.Graphics对象。

解决方案

1. 修改DrawItem事件处理

完全重绘列表项,不依赖系统默认绘制,同时跳过焦点边框的绘制:

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

    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
    e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
    e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
    e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;

    // 不调用e.DrawBackground(),避免系统绘制默认焦点边框
    Color backColor = ((e.State & DrawItemState.Selected) == DrawItemState.Selected) 
        ? DropHoverColor 
        : DropColor;

    using (SolidBrush backBrush = new SolidBrush(backColor))
    {
        e.Graphics.FillRectangle(backBrush, e.Bounds);
    }

    string itemText = base.GetItemText(base.Items[e.Index]);
    using (SolidBrush textBrush = new SolidBrush(ForeColor))
    {
        e.Graphics.DrawString(itemText, Font, textBrush, 
            new RectangleF(e.Bounds.X + 8, e.Bounds.Y, e.Bounds.Width - 8, e.Bounds.Height - 5), 
            StringAlignment.BottomLeft);
    }

    // 不要释放e.Graphics,这是系统提供的对象
}

2. 修正WndProc中的0x0134消息处理

WM_CTLCOLORLISTBOX消息需要返回一个画刷句柄,让系统使用该画刷绘制下拉列表背景,从而避免蓝色边框:

// 新增成员变量存储背景画刷,避免重复创建
private SolidBrush _listBoxBackBrush;

[DllImport("gdi32.dll")]
static extern int SetBkMode(IntPtr hdc, int mode);

public CxFlatComboBoxEnhanced()
{
    DrawItem += CxFlatComboBoxEnhanced_DrawItem;
    SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.ResizeRedraw | ControlStyles.OptimizedDoubleBuffer, true);
    DoubleBuffered = true;
    FlatStyle = FlatStyle.Flat;
    DrawMode = DrawMode.OwnerDrawFixed;
    ItemHeight = 30;
    // 初始化自定义属性默认值
    DropArrowColor = Color.Black;
    DropColor = Color.White;
    DropHoverColor = Color.Gray;
    _listBoxBackBrush = new SolidBrush(DropColor);
}

protected override void WndProc(ref Message m)
{
    // 处理WM_CTLCOLORLISTBOX消息,返回自定义背景画刷
    if (m.Msg == 0x0134)
    {
        // 设置背景模式为透明,避免系统绘制默认边框
        SetBkMode(m.WParam, 1); // TRANSPARENT
        // 返回自定义背景画刷的句柄
        m.Result = _listBoxBackBrush.Handle;
        return; // 跳过base.WndProc,避免系统默认处理
    }

    base.WndProc(ref m);

    if (m.Msg == 0x000F || m.Msg == 0x133)
    {
        IntPtr hDC = GetWindowDC(m.HWnd);
        if (hDC.ToInt32() == 0) return;

        using (Graphics graphics = Graphics.FromHdc(hDC))
        {
            graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.Clear(Parent.BackColor);

            GraphicsPath backPath = DrawHelper.CreateRoundRect(1, 1, Width - 2, Height - 2, 2);
            using (SolidBrush backBrush = new SolidBrush(BackColor))
            {
                graphics.FillPath(backBrush, backPath);
            }
            using (Pen backPen = new Pen(BackColor, 2))
            {
                graphics.DrawPath(backPen, backPath);
            }

            using (SolidBrush textBrush = new SolidBrush(ForeColor))
            {
                graphics.DrawString(Text, Font, textBrush, new Point(8, 8));
            }

            using (Pen arrowPen = new Pen(DropArrowColor, 1))
            {
                if (DroppedDown)
                {
                    graphics.DrawLine(arrowPen, Width - 22, Height / 2 + 2, Width - 17, 15);
                    graphics.DrawLine(arrowPen, Width - 12, Height / 2 + 2, Width - 17, 15);
                }
                else
                {
                    graphics.DrawLine(arrowPen, Width - 22, Height / 2 - 3, Width - 17, 20);
                    graphics.DrawLine(arrowPen, Width - 12, Height / 2 - 3, Width - 17, 20);
                }
            }
        }
        ReleaseDC(m.HWnd, hDC);
    }
}

// 重写Dispose方法,释放自定义画刷
protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        _listBoxBackBrush?.Dispose();
    }
    base.Dispose(disposing);
}

关键说明

  • 移除e.DrawBackground()是避免系统绘制默认焦点边框的核心,所有绘制逻辑完全由自己控制。
  • WM_CTLCOLORLISTBOX消息返回自定义画刷,让系统使用该画刷绘制下拉背景,彻底替代系统默认样式。
  • 使用using语句自动释放GDI资源,避免内存泄漏;不要释放系统提供的e.Graphics对象。
  • 重写Dispose方法释放自定义创建的_listBoxBackBrush,确保资源完全回收。

内容的提问来源于stack exchange,提问作者M Z

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 16:15:56