【Winform】OwnerDraw(自绘) 的用法

Windows Forms 里,OwnerDraw(自绘) 是提升性能和灵活控制 UI 的关键技术之一,尤其适合你关心的"改样式但不影响性能"。

我直接给你讲清楚它的原理 + 使用方式 + 性能注意点


一、OwnerDraw 是什么(本质)

OwnerDraw = 控件不再用系统默认绘制,而是你自己画

👉 系统默认:

  • Button / ListBox / ComboBox → Windows 负责画
  • 样式受限(颜色、边框、主题)

👉 OwnerDraw:

  • 你接管绘制(GDI+)
  • 可以完全自定义 UI(类似轻量级前端)

二、典型支持 OwnerDraw 的控件

WinForms 原生支持:

  • ListBox
  • ComboBox
  • MenuItem
  • TabControl(部分)
  • ListView(高级)

三、最常见示例(ListBox OwnerDraw)

1️⃣ 开启 OwnerDraw

csharp 复制代码
listBox1.DrawMode = DrawMode.OwnerDrawFixed;

2️⃣ 处理绘制事件

csharp 复制代码
private void listBox1_DrawItem(object sender, DrawItemEventArgs e)
{
    if (e.Index < 0) return;

    e.DrawBackground();

    string text = listBox1.Items[e.Index].ToString();

    // 自定义颜色
    Brush brush = ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
        ? Brushes.White
        : Brushes.Black;

    e.Graphics.DrawString(text, e.Font, brush, e.Bounds);

    e.DrawFocusRectangle();
}

四、OwnerDraw 两种模式区别

1️⃣ OwnerDrawFixed

  • 每一项高度固定
  • 性能最好 ✅
  • 推荐默认用这个

2️⃣ OwnerDrawVariable

  • 每项高度不同
  • 需要处理 MeasureItem
  • 性能稍差

五、性能优化关键点(重点)

✅ 1. 不要在 DrawItem 里 new 对象

错误:

csharp 复制代码
Brush b = new SolidBrush(Color.Red); // ❌ 每次绘制都创建

优化:

csharp 复制代码
private static readonly Brush redBrush = Brushes.Red;

✅ 2. 不要做业务逻辑

DrawItem 应该是"纯绘制"

❌ 错误:

csharp 复制代码
var data = LoadFromDB(); // 绝对不要

✔ 正确:

  • 数据提前准备好
  • DrawItem 只读取

✅ 3. 减少字符串处理

csharp 复制代码
// ❌ 每次 ToString / 拼接
string text = item.Name + " - " + item.Id;

👉 建议:

  • 提前缓存显示文本

✅ 4. 控制重绘范围

不要动不动:

csharp 复制代码
listBox1.Refresh(); // ❌

👉 用:

csharp 复制代码
listBox1.Invalidate(rect); // 局部刷新

✅ 5. 避免透明和复杂渐变

GDI+ 中:

  • 渐变刷(LinearGradientBrush)成本高
  • 半透明更慢

👉 高性能方案:

  • 纯色 + 简单边框

六、进阶:绘制更复杂 UI(图标 + 多行)

csharp 复制代码
var item = (MyItem)listBox1.Items[e.Index];

// 图标
e.Graphics.DrawImage(item.Icon, e.Bounds.Left, e.Bounds.Top);

// 主标题
e.Graphics.DrawString(item.Title, boldFont, Brushes.Black, e.Bounds.Left + 40, e.Bounds.Top);

// 副标题
e.Graphics.DrawString(item.SubTitle, smallFont, Brushes.Gray, e.Bounds.Left + 40, e.Bounds.Top + 20);

👉 这就是"模拟现代 UI"的方式


七、OwnerDraw vs 普通控件(性能对比)

方式 控件数量 灵活性 性能
默认控件
修改属性 ⚠️
OwnerDraw

👉 核心优势:
用一个 ListBox ≈ 替代几十个 Label


八、什么时候必须用 OwnerDraw?

建议使用场景:

✔ 大量列表(上百项)

✔ 自定义样式(颜色/图标/多行)

✔ 高频刷新 UI

✔ 想避免卡顿


九、一句话总结

OwnerDraw 的本质是:用绘制换控件数量 → 用 CPU 换 GDI 句柄 → 性能更可控


相关推荐
Jp7gnUWcI2 小时前
基于.NET操作Excel COM组件生成数据透视报表
.net·excel
tHeya06II4 小时前
.NET AI 核心构建块:重塑智能应用开发的架构范式与生态
人工智能·架构·.net
wd5i8kA8i5 小时前
.NET 10 New feature 新增功能介绍-Minimal APIs增强
.net
UAq6wn76j6 小时前
.NET源码生成器使用SyntaxTree生成代码及简化语法
java·开发语言·.net
QfC92C02p7 小时前
C# 中的 Span 和内存:.NET 中的高性能内存处理
java·c#·.net
刚子编程8 小时前
.NET 8 性能优化实战:让你的应用起飞
性能优化·.net
公子小六8 小时前
基于.NET的Windows窗体编程之WinForms布局简介
windows·microsoft·c#·.net
Jp7gnUWcI9 小时前
基于NativeAOT的 OpenClaw.NET 深度刨析
.net
tq6J5Yg149 小时前
.NET 10 & C# 14 New Features 新增功能介绍-带修饰符的简单 lambda 参数
开发语言·c#·.net