当 Run.Text 仅包含一个 space 字符时,如何将 RichTextBox.Caret 设置为 Run.ContentStart
How to set RichTextBox.Caret to a Run.ContentStart, when Run.Text contain only an space-character
我有一个这样的 FlowDocument:
<FlowDocument>
<Paragraph>
<Span>
<Run Background="#FFFFDAB9">{</Run>
<Run Background="#FFB0E0E6">a</Run>
<Run FontWeight="Bold" Background="#FFFFDAB9">||</Run>
<Run Background="#FFB0E0E6">b</Run>
<Run Background="#FFFFDAB9">}</Run>
</Span>
</Paragraph>
</FlowDocument>
当我将 RichTextBox.Caret 设置为第二个 Run.ContentStart(在“a”字符之前)时,一切正常。但是,当我将字符“a”替换为“”(简单的 space 字符)时,我无法再将插入符号放置到 运行.
的 ContentStart 中
<FlowDocument>
<Paragraph>
<Span>
<Run Background="#FFFFDAB9">{</Run>
<Run Background="#FFB0E0E6" xml:space="preserve"> </Run>
<Run FontWeight="Bold" Background="#FFFFDAB9">||</Run>
<Run Background="#FFB0E0E6">b</Run>
<Run Background="#FFFFDAB9">}</Run>
</Span>
</Paragraph>
</FlowDocument>
插入符将保留在“}”(第一个 Run.ContentEnd)后面。
我制作了一个简单的“调试”功能来显示和设置 RichTextBox.Caret。要对此进行测试,您必须替换换行符,因此您有一个单行 XAML。我刚刚格式化了 XAML 以提高可读性。
Private Sub SetRichTextBoxCarret(thisRTB As RichTextBox, thisTP As TextPointer, Optional additionalOffset As Int32 = 0)
Dim myDirection = If(CBool(thisRTB.CaretPosition.LogicalDirection), LogicalDirection.Backward, LogicalDirection.Forward)
Debug.WriteLine("")
Debug.WriteLine(String.Format("SetRichTextBoxCarret - TextPointerOffset: {0}", thisRTB.Document.ContentStart.GetOffsetToPosition(thisTP)))
Debug.WriteLine(String.Format("SetRichTextBoxCarret - TextPointerText: {0}", thisTP.GetTextInRun(myDirection)))
Debug.WriteLine(String.Format("SetRichTextBoxCarret - CaretOffset Before: {0}", thisRTB.Document.ContentStart.GetOffsetToPosition(thisRTB.CaretPosition)))
Dim myDestinationPosition = thisTP.GetPositionAtOffset(additionalOffset, myDirection)
thisRTB.CaretPosition = myDestinationPosition
Debug.WriteLine(String.Format("SetRichTextBoxCarret - CaretOffset After: {0}", thisRTB.Document.ContentStart.GetOffsetToPosition(thisRTB.CaretPosition)))
End Sub
我是这样称呼这个套路的(举例)
Private Sub Set1_Click(sender As Object, e As RoutedEventArgs)
Dim myRTB = Me.rtbSearchCriteria1
Dim myParagraph = DirectCast(myRTB.Document.Blocks(0), Paragraph)
Dim mySpan = DirectCast(myParagraph.Inlines(0), Span)
Dim myRun = DirectCast(mySpan.Inlines(1), Run)
myRTB.Focus()
SetRichTextBoxCarret(myRTB, myRun.ContentStart)
End Sub
在输出中显示以下内容 window:
SetRichTextBoxCarret - TextPointerOffset: 6
SetRichTextBoxCarret - TextPointerText: a
SetRichTextBoxCarret - CaretOffset Before: 3
SetRichTextBoxCarret - CaretOffset After: 6
但是,当我有第二个 Flowdocument(使用 space 字符而不是“a”字符)时,我会得到这个
SetRichTextBoxCarret - TextPointerOffset: 6
SetRichTextBoxCarret - TextPointerText:
SetRichTextBoxCarret - CaretOffset Before: 3
SetRichTextBoxCarret - CaretOffset After: 4
插入符号距离“myRun.ContentStart”有 2 个符号。没有办法到达这个位置。
我已经阅读了很多关于 TextPointers 的文章,文档中说“文本 运行 元素中的每个 16 位 Unicode 字符”。据我所知,space 字符是一个 Unicode 字符,它显然位于 运行 元素内。
我是不是遗漏了什么,或者这只是一个错误?有没有办法禁用 RichTextBox 中的“插入符号位置重新定位”?
当我调用“RichTextBox.Selection.Select(myDestinationPosition, myDestinationPosition) 时,它的行为方式相同。而且 .NextInsertPosition 或 .NextContextPosition 也不可能。然后插入符号将越过 Run.ContentStart。
是的 - 我尝试做一些简单的语法高亮显示
我在这里做了一个简单的DemoApp:DemoApp
此问题的根源是 RichTextBox Class。 RichTextBox.CaretPosition
获取一个 TextPointer 并调用具有以下定义的 Selection.SetCaretToPosition
:void SetCaretToPosition(ITextPointer caretPosition, LogicalDirection direction, bool allowStopAtLineEnd, bool allowStopNearSpace);
但是在 RichTextBox Class 中,它被硬编码为不设置在 space-字符附近:Selection.SetCaretToPosition(value, value.LogicalDirection, true, false
。 see here
我提到 MS 在 RichTextBox Class 中创建属性,因此我们可以在需要时配置 Selection.SetCaretToPosition
的最后 2 个参数。
解决方案: 经过漫长的“试错”之路后,我最好的解决方案是用引号替换 space。例如<Run Background="#FFB0E0E6">""</Run>
.
一方面,这解决了 space-chars 的问题,另一方面,对于用户来说,写在哪里更清楚。
此外,当用户使用光标键输入 Run
或单击错误的位置时,我添加了一些代码以将插入符放在 2 个引号之间。
我有一个这样的 FlowDocument:
<FlowDocument>
<Paragraph>
<Span>
<Run Background="#FFFFDAB9">{</Run>
<Run Background="#FFB0E0E6">a</Run>
<Run FontWeight="Bold" Background="#FFFFDAB9">||</Run>
<Run Background="#FFB0E0E6">b</Run>
<Run Background="#FFFFDAB9">}</Run>
</Span>
</Paragraph>
</FlowDocument>
当我将 RichTextBox.Caret 设置为第二个 Run.ContentStart(在“a”字符之前)时,一切正常。但是,当我将字符“a”替换为“”(简单的 space 字符)时,我无法再将插入符号放置到 运行.
的 ContentStart 中<FlowDocument>
<Paragraph>
<Span>
<Run Background="#FFFFDAB9">{</Run>
<Run Background="#FFB0E0E6" xml:space="preserve"> </Run>
<Run FontWeight="Bold" Background="#FFFFDAB9">||</Run>
<Run Background="#FFB0E0E6">b</Run>
<Run Background="#FFFFDAB9">}</Run>
</Span>
</Paragraph>
</FlowDocument>
插入符将保留在“}”(第一个 Run.ContentEnd)后面。
我制作了一个简单的“调试”功能来显示和设置 RichTextBox.Caret。要对此进行测试,您必须替换换行符,因此您有一个单行 XAML。我刚刚格式化了 XAML 以提高可读性。
Private Sub SetRichTextBoxCarret(thisRTB As RichTextBox, thisTP As TextPointer, Optional additionalOffset As Int32 = 0)
Dim myDirection = If(CBool(thisRTB.CaretPosition.LogicalDirection), LogicalDirection.Backward, LogicalDirection.Forward)
Debug.WriteLine("")
Debug.WriteLine(String.Format("SetRichTextBoxCarret - TextPointerOffset: {0}", thisRTB.Document.ContentStart.GetOffsetToPosition(thisTP)))
Debug.WriteLine(String.Format("SetRichTextBoxCarret - TextPointerText: {0}", thisTP.GetTextInRun(myDirection)))
Debug.WriteLine(String.Format("SetRichTextBoxCarret - CaretOffset Before: {0}", thisRTB.Document.ContentStart.GetOffsetToPosition(thisRTB.CaretPosition)))
Dim myDestinationPosition = thisTP.GetPositionAtOffset(additionalOffset, myDirection)
thisRTB.CaretPosition = myDestinationPosition
Debug.WriteLine(String.Format("SetRichTextBoxCarret - CaretOffset After: {0}", thisRTB.Document.ContentStart.GetOffsetToPosition(thisRTB.CaretPosition)))
End Sub
我是这样称呼这个套路的(举例)
Private Sub Set1_Click(sender As Object, e As RoutedEventArgs)
Dim myRTB = Me.rtbSearchCriteria1
Dim myParagraph = DirectCast(myRTB.Document.Blocks(0), Paragraph)
Dim mySpan = DirectCast(myParagraph.Inlines(0), Span)
Dim myRun = DirectCast(mySpan.Inlines(1), Run)
myRTB.Focus()
SetRichTextBoxCarret(myRTB, myRun.ContentStart)
End Sub
在输出中显示以下内容 window:
SetRichTextBoxCarret - TextPointerOffset: 6
SetRichTextBoxCarret - TextPointerText: a
SetRichTextBoxCarret - CaretOffset Before: 3
SetRichTextBoxCarret - CaretOffset After: 6
但是,当我有第二个 Flowdocument(使用 space 字符而不是“a”字符)时,我会得到这个
SetRichTextBoxCarret - TextPointerOffset: 6
SetRichTextBoxCarret - TextPointerText:
SetRichTextBoxCarret - CaretOffset Before: 3
SetRichTextBoxCarret - CaretOffset After: 4
插入符号距离“myRun.ContentStart”有 2 个符号。没有办法到达这个位置。
我已经阅读了很多关于 TextPointers 的文章,文档中说“文本 运行 元素中的每个 16 位 Unicode 字符”。据我所知,space 字符是一个 Unicode 字符,它显然位于 运行 元素内。
我是不是遗漏了什么,或者这只是一个错误?有没有办法禁用 RichTextBox 中的“插入符号位置重新定位”?
当我调用“RichTextBox.Selection.Select(myDestinationPosition, myDestinationPosition) 时,它的行为方式相同。而且 .NextInsertPosition 或 .NextContextPosition 也不可能。然后插入符号将越过 Run.ContentStart。
是的 - 我尝试做一些简单的语法高亮显示
我在这里做了一个简单的DemoApp:DemoApp
此问题的根源是 RichTextBox Class。 RichTextBox.CaretPosition
获取一个 TextPointer 并调用具有以下定义的 Selection.SetCaretToPosition
:void SetCaretToPosition(ITextPointer caretPosition, LogicalDirection direction, bool allowStopAtLineEnd, bool allowStopNearSpace);
但是在 RichTextBox Class 中,它被硬编码为不设置在 space-字符附近:Selection.SetCaretToPosition(value, value.LogicalDirection, true, false
。 see here
我提到 MS 在 RichTextBox Class 中创建属性,因此我们可以在需要时配置 Selection.SetCaretToPosition
的最后 2 个参数。
解决方案: 经过漫长的“试错”之路后,我最好的解决方案是用引号替换 space。例如<Run Background="#FFB0E0E6">""</Run>
.
一方面,这解决了 space-chars 的问题,另一方面,对于用户来说,写在哪里更清楚。
此外,当用户使用光标键输入 Run
或单击错误的位置时,我添加了一些代码以将插入符放在 2 个引号之间。