我扩展了 RichTextBox 控件以实现本地 RichEdit 类中提供的许多缺失功能。
我遇到了一个问题,如果控件设置为换行到窗口或换行到打印机,水平滚动条会出现,即使在调整控件大小时它不应该出现。
将 wordwrap 循环到 none 并返回似乎可以解决问题,但在换行到打印机时可能会相对较慢(即:调用每个 Resize 事件的速度太慢了)。
这是我的自动换行代码:
private void ChangeWordWrap(WordWrap wordWrap)
{
switch (wordWrap)
{
case WordWrap.NoWrap:
{
User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_SETTARGETDEVICE, 0, 1);
break;
}
case WordWrap.WrapToPrintDocument:
{
using (Graphics g = PrintDocument.PrinterSettings.CreateMeasurementGraphics(PrintDocument.DefaultPageSettings))
{
int lParam = ConvertEx.HundredthInchToTwips((PrintDocument.DefaultPageSettings.Bounds.Width - PrintDocument.DefaultPageSettings.Margins.Left - PrintDocument.DefaultPageSettings.Margins.Right));
IntPtr wParam = g.GetHdc();
User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_SETTARGETDEVICE, wParam, lParam);
g.ReleaseHdc();
}
break;
}
case WordWrap.WrapToControl:
{
User32.SendMessage(_RichTextBox.Handle, ApiConstants.EM_SETTARGETDEVICE, 0, 0);
break;
}
}
}
最初我认为问题可能与我正在释放图形句柄的事实有关,但是当我包装到控件并且不需要句柄时也会出现问题。
添加截图:
正确行为:
不正确的行为(在非常轻微地调整表单大小之后):
换行到窗口/无换行代码来自http://msdn.microsoft.com/en-us/library/bb774282(VS.85).aspx上的评论
调用 ::SendMessage(hwnd, EM_SETTARGETDEVICE, NULL, 0) 会将文本换行到窗口,而 ::SendMessage(hwnd, EM_SETTARGETDEVICE, NULL, 1) 将完全禁用自动换行。我不确定这是否记录在其他任何地方。
我的 p/invoke:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);
相关常数:
public const int WM_USER = 0x400;
public const int EM_SETTARGETDEVICE = (WM_USER + 72);
编辑:
我一直在研究这个,我相信 .NET RichTextBox 控件在调整控件大小时可能会发送带有不正确值的 SetScrollRange()。这是有道理的,因为它不一定知道 EM_SETTARGETDEVICE 消息。
我可能会在调整大小后执行 SetScrollRange() 或类似的东西,但我的问题是我不知道正确的值是什么,也不知道如何弄清楚。
我注意到的另一件事是,当问题发生时,我可以将控件的大小调整为实际包裹文本的大小。此时滚动条回到功能状态,我可以调整大小,直到自动换行循环为无并返回。
编辑:(下面我的非功能性答案中还有更多细节)
看起来 EM_GETRECT 不是我真正想要的,因为当控件大小发生变化时它的大小也会发生变化。这是 MSDN 的描述:
EM_GETRECT 消息
获取编辑控件的格式矩形。格式化矩形是控件在其中绘制文本的限制矩形。限制矩形与编辑控制窗口的大小无关。您可以将此消息发送到编辑控件或富编辑控件。
我最初的理解是,这是整个文本的矩形,从中我可以确定客户端窗口是否小于格式化矩形,因此应该显示滚动条。
看起来这个格式化矩形的真正目的是使文本显示在一个小于编辑控件的区域(即:边距)。
新问题:
那么,有没有我认为 EM_GETRECT 会给我的矩形?一个矩形会告诉我文本(包括超出屏幕的部分)有多宽?例如,如果我有一个 400 像素的控件和一行 800 像素长的文本,我想获得 800 像素的值,以便我可以将它与控件宽度进行比较并显示/不显示滚动条。
实际上,我并不关心非控制文本的长度,而是关心知道IF文本超出了控件的范围。
感谢到目前为止的所有帮助。