【发布时间】:2020-04-30 11:12:05
【问题描述】:
我有一个应用程序以管道格式 (HL7) 分析数据消息,为此,它有一个与 RichTextBox 同步的 DataGridView。具体来说,当你点击DataGridView中的某个属性时,会跳转到RichTextBox中的对应位置,反之亦然。
RichTextBox 禁用了自动换行,因此我可以轻松地将编辑器中的行与实际数据中的行匹配。
但是,我目前必须处理在某些部分包含二进制文件的 Base64 转储的消息,而且大内容使富文本框无论如何都会换行。这使计算变得混乱,并且当匹配实际消息文本中的返回位置时,我得到错误的数据,分析失败,并且通常,当实际的下一行短于单击的位置时,我得到一个ArgumentOutOfRangeException那条线。
这是代码:
/// <summary>Gets the cursor position as Point, with Y as line number and X as index on that line.</summary>
/// <returns>The cursor position as Point, with Y as line number and X as index on that line</returns>
protected Point GetCursorPosition()
{
Int32 selectionStart = this.rtxtMessage.SelectionStart;
Int32 currentLine = this.rtxtMessage.GetLineFromCharIndex(selectionStart);
Int32 currentPos = selectionStart - this.rtxtMessage.GetFirstCharIndexFromLine(currentLine);
return new Point(currentPos, currentLine);
}
正确的行为:
点击后,函数将返回点[28, 4]。
强制换行的错误行为:
在这次点击中,函数将返回点 [6,5],它实际上应该是 [2813,4]。这会导致它显示下一行的分析,并且如前所述,如果点击是在该行中超出下一个分析行末尾的位置上,则会导致ArgumentOutOfRangeException。
有什么办法可以弥补这种强制线分割?我需要能够准确地确定实际文本中的位置才能进行分析。
请注意,分行似乎不可预测;我不知道它尝试拆分的最大长度是多少,或者它决定拆分的字符是可能的。
另请注意,两个称为RichTextBox 的函数,即GetLineFromCharIndex 和GetFirstCharIndexFromLine,正确对应于屏幕上实际显示的内容......但屏幕上显示的内容是真实数据的不正确表示。事实上,它甚至不对应于RichTextBox 自己的.Lines 属性的输出,它为我提供了纯文本行数组中的内容。
我宁愿避免使用 .Lines 属性,因为我注意到通常从富文本框中提取文本的函数相当慢。
【问题讨论】:
-
EM_SETWORDBREAKPROC -- How to Use Word and Line Break Information(请参阅警告,即使此处不适用)。如果委托函数未正确实现(在自定义控件中),您将获得 random 异常。对于委托指针,可以使用Marshal.GetFunctionPointerForDelegate。
-
我怀疑一旦文本超过底层 RichEdit 控件的formatting rectangle,它就会强制换行。也许您可以颠倒您的逻辑并使用 DGV 作为导航源并显示 3 个堆叠的 RTB(当前 DGV 行之前的行、当前行、下一行)?
-
IIRC,如果代理总是返回 0,那么你在任何地方都没有换行符。
-
@TnTinMn 导航实际上是双向的:在文本中点击跳转到datagrid中的属性分析,在datagrid中点击跳转到文本中所选属性的开头。由于该工具的主要目的是轻松识别管道数据,因此文本侧导航绝对至关重要。
-
比这差得多。 RichEdit 控件不提供该信息(TextBox 控件也不提供),它只是索引字符位置(换行符在内部处理,它也不是公共信息,您需要实现自己的换行例程来处理这些信息,使用
EditWordBreakDelegate,如前所述),因此每次您请求Lines[]属性时,this is what happens。如果您的文本很长,这会阻止您使用该属性。
标签: c# winforms richtextbox