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

如何让WinForms RichTextBox无需高亮即可正确绘制文本行?

问题原因

这是System.Windows.Forms.RichTextBox控件的已知原生渲染缺陷,并非你的代码逻辑错误:当控件在短时间内接收大量文本插入时,内部的行高计算、排版缓存与窗口绘制区域的更新逻辑会出现不同步,导致中间可视区域的绘制指令被丢弃,只有滚动、选中这类强制触发全区域重绘的操作才能让内容正常显示。

你用WM_SETREDRAW暂停重绘的优化方向是正确的,只是缺少了恢复重绘后的补全操作,加上以下优化即可解决:

修复方案

1. 完善WM_SETREDRAW的调用逻辑

恢复重绘后主动触发控件全区域重绘,修正排版缓存与显示的不同步:

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(HandleRef hWnd, Int32 Msg, IntPtr wParam, IntPtr lParam);

const int WM_SETREDRAW = 0x000B;
HandleRef consoleHandle = new HandleRef(this.console, this.console.Handle);

// 暂停重绘
SendMessage(consoleHandle, WM_SETREDRAW, IntPtr.Zero, IntPtr.Zero);
try
{
    // 推荐:先拼接所有待追加文本,一次性插入,不要循环调用AppendText
    string batchContent = "你要批量插入的所有行拼接后的内容";
    this.console.AppendText(batchContent);
}
finally
{
    // 恢复重绘
    SendMessage(consoleHandle, WM_SETREDRAW, new IntPtr(1), IntPtr.Zero);
    // 强制全区域重绘
    this.console.Invalidate();
    this.console.Update();
    // 可选:如果需要自动滚动到末尾
    this.console.ScrollToCaret();
}

2. 开启控件双缓冲(可选,进一步减少闪烁和绘制异常)

RichTextBox默认未开启双缓冲,可通过反射设置该属性,放在窗体初始化逻辑中执行一次即可:

// 注:需要先引用System.Reflection命名空间
typeof(RichTextBox).InvokeMember(
    "DoubleBuffered",
    BindingFlags.SetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
    null,
    this.console,
    new object[] { true });

3. 增加文本更新缓冲区(超高频插入场景推荐)

如果插入频率确实达到每秒数百行,可做一个简单的内存队列缓冲,每隔30~50ms批量拼接一次文本再插入控件,从源头降低控件的更新频率,既缓解渲染压力也减少CPU占用。

现象参考

  • 异常状态:
    高亮前
  • 选中后强制重绘恢复正常:
    高亮后

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 12:09:03