【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 句柄 → 性能更可控


相关推荐
hez20101 天前
.NET 11 Runtime Async 详解
c#·.net·.net core
猿长大人1 天前
C# | Serilog 新手入门
开发语言·c#·.net·log
猿长大人2 天前
C# | Autofac 新手指南:从零理解依赖注入与组件装配
c#·.net·di·依赖注入
半亩码田3 天前
【.NET新特性·第10篇】.NET 10 概览:LTS 版本的全面进化
大数据·.net
回忆2012初秋4 天前
.NET 中 TAP:构建健壮后台任务(BackgroundService)的完全指南(二)
网络·.net
猿长大人4 天前
C# | MediatR 入门指南:后端架构解耦
分布式·后端·架构·c#·.net
海盗12344 天前
微软技术日报——2026-08-06
人工智能·microsoft·.net
猿长大人5 天前
C# | 函数式编程入门
开发语言·c#·.net
L歪歪君 山水甲天6 天前
Office文件的奥秘——.NET平台下不借助Office实现Word、Powerpoint等文件的解析(1)
word·powerpoint·.net