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


相关推荐
qq_431280702 小时前
工作经验总结:半导体上位机软件开发与互联网开发的不同
c#·.net
ironinfo3 小时前
.net 高并发服务性能瓶颈排查处理
性能优化·.net·grpc
回忆2012初秋3 小时前
【.Net】一文讲清楚SonnetDB 时序库的使用
.net
雪飞鸿1 天前
ArrayPoolWrapper简洁、安全的ArrayPool
c#·.net·.net core·原创
我是唐青枫1 天前
C#.NET MemoryMarshal 深入解析:零拷贝内存重解释、二进制读写与使用边界
c#·.net
步步为营DotNet1 天前
深入剖析.NET 11 中 Semantic Kernel 于智能后端集成的创新实践
前端·.net·easyui
喵叔哟1 天前
10.【.NET10 实战--孢子记账--产品智能化】--其余第三方包批量升级
人工智能·.net
武藤一雄1 天前
WPF中逻辑树(Logical Tree)与可视化树(Visual Tree)到底是什么
microsoft·c#·.net·wpf·.netcore
软泡芙1 天前
【.NET】创建一个ai聊天应用
人工智能·flask·.net