我有一个应用程序以管道格式(HL7)分析数据消息,为此,它具有与DataGridView
同步的RichTextBox
。具体来说,当您单击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
属性,因为我注意到一般来说,从富文本框中提取文本的功能相当慢。
已经访问该属性以进行随机操作,尤其是在发生任何行更改的分析部分。
我决定为该行数组设置一个缓存变量,该变量在TextChanged
的RichTextBox
事件中被清除。然后,将所有提取了RichTextBox
上的行的实例替换为对该小函数的调用:
private String[] GetTextboxLines()
{
if (this.m_LineCache != null)
return this.m_LineCache;
String[] lines = this.rtxtMessage.Lines;
this.m_LineCache = lines;
return lines;
}
仅在富文本编辑器中键入文本时,这仍然很繁重,因为任何按键都会基本上清除数组,然后分析器操作将再次读取该数组,但是由于该工具首先是分析器,然后才是编辑器,这不是一个大问题。即便如此,在这样的按键之后,RichTextBox.Lines
在分析中也被多次调用,因此总体上,结果[有了这个系统,在我的小GetCursorPosition()
函数中再次使用lines数组变得可行,因此我也对其进行了调整,以利用新的缓存值:
/// <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;
String[] lines = this.GetTextboxLines();
Int32 nrOfLines = lines.Length;
Int32 y;
for (y = 0; y < nrOfLines; y++)
{
Int32 lineLen = lines[y].Length;
// Can be equal if at the very end of a line.
if (selectionStart <= lineLen)
return new Point(selectionStart, y);
// +1 to compensate for the line break character,
// which is only one byte in a rich text box.
selectionStart -= (lineLen + 1);
}
return new Point(0, nrOfLines - 1);
}