我需要在RichTextBox中追加文本,而且需要在不使文本框滚动或失去当前文本选择的情况下执行,这是否可能?
在WinForms中,RichTextBox在使用文本和选取文本方法时会出现很多闪烁。
我有一个标准的替代方案,可以通过以下代码关闭绘制和滚动:
class RichTextBoxEx: RichTextBox
{
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);
const int WM_USER = 0x400;
const int WM_SETREDRAW = 0x000B;
const int EM_GETEVENTMASK = WM_USER + 59;
const int EM_SETEVENTMASK = WM_USER + 69;
const int EM_GETSCROLLPOS = WM_USER + 221;
const int EM_SETSCROLLPOS = WM_USER + 222;
Point _ScrollPoint;
bool _Painting = true;
IntPtr _EventMask;
int _SuspendIndex = 0;
int _SuspendLength = 0;
public void SuspendPainting()
{
if (_Painting)
{
_SuspendIndex = this.SelectionStart;
_SuspendLength = this.SelectionLength;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref _ScrollPoint);
SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
_EventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
_Painting = false;
}
}
public void ResumePainting()
{
if (!_Painting)
{
this.Select(_SuspendIndex, _SuspendLength);
SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref _ScrollPoint);
SendMessage(this.Handle, EM_SETEVENTMASK, 0, _EventMask);
SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
_Painting = true;
this.Invalidate();
}
}
}
然后,通过我的表单,我可以愉快地拥有一个无闪烁的富文本框控件:
richTextBoxEx1.SuspendPainting();
richTextBoxEx1.AppendText("Hey!");
richTextBoxEx1.ResumePainting();
这个解决方案几乎完美,但是它没有正确处理反向选择(即插入符号在选择的开头而不是结尾 - 例如使用SHIFT+LEFT或向上拖动鼠标选择文本)。
这里是一个改进版本,增加了以下功能:
这意味着您可以将插入符号放在文本末尾并监视添加的文本(考虑日志文件监视)。 这也意味着您可以使用CTRL+A选择所有内容,并自动将任何附加的文本包含在您的选择中。
class RichTextBoxEx : RichTextBox
{
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);
[DllImport("user32")]
private static extern int GetCaretPos(out Point p);
const int WM_USER = 0x400;
const int WM_SETREDRAW = 0x000B;
const int EM_GETEVENTMASK = WM_USER + 59;
const int EM_SETEVENTMASK = WM_USER + 69;
const int EM_GETSCROLLPOS = WM_USER + 221;
const int EM_SETSCROLLPOS = WM_USER + 222;
private Point oScrollPoint;
private bool bPainting = true;
private IntPtr oEventMask;
private int iSuspendCaret;
private int iSuspendIndex;
private int iSuspendLength;
private bool bWasAtEnd;
public int CaretIndex
{
get
{
Point oCaret;
GetCaretPos(out oCaret);
return this.GetCharIndexFromPosition(oCaret);
}
}
public void AppendTextWithoutScroll(string text)
{
this.SuspendPainting();
this.AppendText(text);
this.ResumePainting();
}
private void SuspendPainting()
{
if (this.bPainting)
{
this.iSuspendCaret = this.CaretIndex;
this.iSuspendIndex = this.SelectionStart;
this.iSuspendLength = this.SelectionLength;
this.bWasAtEnd = this.iSuspendIndex + this.iSuspendLength == this.TextLength;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref this.oScrollPoint);
SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
this.oEventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
this.bPainting = false;
}
}
private void ResumePainting()
{
if (!this.bPainting)
{
if (this.iSuspendLength == 0)
{
if (!bWasAtEnd)
{
this.Select(this.iSuspendIndex, 0);
}
}
else
{
// Original selection was to end of text
if (bWasAtEnd)
{
// Maintain end of selection at end of new text
this.iSuspendLength = this.TextLength - this.iSuspendIndex;
}
if (this.iSuspendCaret > this.iSuspendIndex)
{
// Forward select (caret is at end)
this.Select(this.iSuspendIndex, this.iSuspendLength);
}
else
{
// Reverse select (caret is at start)
this.Select(this.iSuspendIndex + this.iSuspendLength, -this.iSuspendLength);
}
}
SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref this.oScrollPoint);
SendMessage(this.Handle, EM_SETEVENTMASK, 0, this.oEventMask);
SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
this.bPainting = true;
this.Invalidate();
}
}
}
基于LarsTech的文章,这里有一些不错的东西:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
namespace yournamespace
{
class RichTextBoxEx : RichTextBox
{
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
[DllImport("user32.dll")]
static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);
const int WM_USER = 0x400;
const int WM_SETREDRAW = 0x000B;
const int EM_GETEVENTMASK = WM_USER + 59;
const int EM_SETEVENTMASK = WM_USER + 69;
const int EM_GETSCROLLPOS = WM_USER + 221;
const int EM_SETSCROLLPOS = WM_USER + 222;
Point _ScrollPoint;
bool _Painting = true;
IntPtr _EventMask;
int _SuspendIndex = 0;
int _SuspendLength = 0;
public bool Autoscroll = true;
public void SuspendPainting()
{
if (_Painting)
{
_SuspendIndex = this.SelectionStart;
_SuspendLength = this.SelectionLength;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref _ScrollPoint);
SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
_EventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
_Painting = false;
}
}
public void ResumePainting()
{
if (!_Painting)
{
this.Select(_SuspendIndex, _SuspendLength);
SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref _ScrollPoint);
SendMessage(this.Handle, EM_SETEVENTMASK, 0, _EventMask);
SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
_Painting = true;
this.Invalidate();
}
}
new public void AppendText(string text) // overwrites RichTextBox.AppendText
{
if (Autoscroll)
base.AppendText(text);
else
{
SuspendPainting();
base.AppendText(text);
ResumePainting();
}
}
}
}
你可以这样使用它:
var textbox = new RichTextBoxEx();
textbox.Autoscroll = false;
textbox.AppendText("Hi");
class RichTextBoxEx : RichTextBox
{
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);
[DllImport("user32")]
private static extern int GetCaretPos(out Point p);
const int WM_USER = 0x400;
const int WM_SETREDRAW = 0x000B;
const int EM_GETEVENTMASK = WM_USER + 59;
const int EM_SETEVENTMASK = WM_USER + 69;
const int EM_GETSCROLLPOS = WM_USER + 221;
const int EM_SETSCROLLPOS = WM_USER + 222;
private Point oScrollPoint;
private bool bPainting = true;
private IntPtr oEventMask;
private int iSuspendCaret;
private int iSuspendIndex;
private int iSuspendLength;
private bool bWasAtEnd;
private Color _selColor = Color.Black;
public int CaretIndex
{
get
{
Point oCaret;
GetCaretPos(out oCaret);
return this.GetCharIndexFromPosition(oCaret);
}
}
new public Color SelectionColor { get { return _selColor; } set { _selColor = value; } }
new public void AppendText(string text) // overwrites RichTextBox.AppendText
{
if (this.SelectionStart >= this.TextLength)
{
base.SelectionColor = _selColor;
base.AppendText(text);
}
else
{
var selStart = this.SelectionStart;
var selLength = this.SelectionLength;
SuspendPainting();
this.Select(this.TextLength, 0);
base.SelectionColor = _selColor;
base.AppendText(text);
this.Select(selStart, selLength);
ResumePainting();
}
}
private void SuspendPainting()
{
if (this.bPainting)
{
this.iSuspendCaret = this.CaretIndex;
this.iSuspendIndex = this.SelectionStart;
this.iSuspendLength = this.SelectionLength;
this.bWasAtEnd = this.iSuspendIndex + this.iSuspendLength == this.TextLength;
SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref this.oScrollPoint);
SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
this.oEventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
this.bPainting = false;
}
}
private void ResumePainting()
{
if (!this.bPainting)
{
if (this.iSuspendLength == 0)
{
if (!bWasAtEnd)
{
this.Select(this.iSuspendIndex, 0);
}
}
else
{
// Original selection was to end of text
if (bWasAtEnd)
{
// Maintain end of selection at end of new text
this.iSuspendLength = this.TextLength - this.iSuspendIndex;
}
if (this.iSuspendCaret > this.iSuspendIndex)
{
// Forward select (caret is at end)
this.Select(this.iSuspendIndex, this.iSuspendLength);
}
else
{
// Reverse select (caret is at start)
this.Select(this.iSuspendIndex + this.iSuspendLength, -this.iSuspendLength);
}
}
SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref this.oScrollPoint);
SendMessage(this.Handle, EM_SETEVENTMASK, 0, this.oEventMask);
SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
this.bPainting = true;
this.Invalidate();
}
}
}
Dim tempStart As Int32
Dim tempLength As Int32
tempStart = RichTextBox1.SelectionStart
tempLength = RichTextBox1.SelectionLength
RichTextBox1.Text += "dsfkljwerhsdlf"
RichTextBox1.SelectionStart = tempStart
RichTextBox1.SelectionLength = tempLength
rtb.Select(rtb.TextLength, 0); rtb.SelectedRtf = @"{\rtf\ansi{\colortbl;\red255\green0\blue0;}\cf1 红色字符\par}";rtb.Select(rtb.TextLength, 0);rtb.SelectionColor = Color.Black;
- LarsTech