如何让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
相关产品推荐
相关产品推荐

