0

I have a FlowDocument like this:

<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>

When I set the RichTextBox.Caret to the second Run.ContentStart (before the "a" char), everything works fine. But when I replace the char "a" with a " " (simple space char), then I'm no longer able to place the Caret to the ContentStart of the Run.

<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>

The Caret will remain behind the "}" (the first Run.ContentEnd).

I made a simple "debug" function to show and set the RichTextBox.Caret. To test this, you have to replace the linebreaks, so you have a single-line XAML. I just formated the XAML for better readability.

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

I call this this routine in this way (for example)

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

which shows the following in the output window:

SetRichTextBoxCarret - TextPointerOffset: 6
SetRichTextBoxCarret - TextPointerText: a
SetRichTextBoxCarret - CaretOffset Before: 3
SetRichTextBoxCarret - CaretOffset After: 6

but, when I have the 2nd Flowdocument (with a space char instead of the "a" char) I'll get this

SetRichTextBoxCarret - TextPointerOffset: 6
SetRichTextBoxCarret - TextPointerText: 
SetRichTextBoxCarret - CaretOffset Before: 3
SetRichTextBoxCarret - CaretOffset After: 4

the caret is 2 symbols away from "myRun.ContentStart". and there is no way to reach this position.

I have read a lot about the TextPointers and the documentation says "Each 16-bit Unicode character inside of a text Run element". As far as I remember, a space char is a Unicode char and it is obviously inside of an run element.

Am I missing something here or is this simply a bug? Is there a way to disable a "caret-position-repositioning" in the RichTextBox?

This behaves the same way when I call "RichTextBox.Selection.Select(myDestinationPosition, myDestinationPosition". Also it is not possible with .NextInsertPosition or .NextContextPosition. The caret will then overjump the Run.ContentStart.

And yes - I try to make some simple Syntax-Highlighting

I made a simple DemoApp here: DemoApp

koldomon
  • 1
  • 2
  • Hmm... Please try to describe your problem more clearly. What exactly are you doing and what doesn't work. You wrote: **_But when I replace the char "a" with a " " (simple space char), then I'm no longer able to place the Caret to the ContentStart of the Run._** If you trying to set the caret to some _Run ContextStart_ from the code show exactly this code. – Jackdaw Jun 21 '21 at 21:30
  • I added the debug output and the call to the routine. I hope this provides more clarity It does not depend, if I call this in an mouse- or keyboard event. all I want is to place the caret, so the user inserts the text at the intended position (blue) and not at the syntax elements (orange). – koldomon Jun 22 '21 at 06:45

1 Answers1

0

The source of this problem is the RichTextBox Class. RichTextBox.CaretPosition takes a TextPointer and calls the Selection.SetCaretToPosition which has this definition: void SetCaretToPosition(ITextPointer caretPosition, LogicalDirection direction, bool allowStopAtLineEnd, bool allowStopNearSpace);

But in the RichTextBox Class it is hardcoded not to set near a space-char: Selection.SetCaretToPosition(value, value.LogicalDirection, true, false. see here

I mentioned MS to make properties in the RichTextBox Class so we can configure the last 2 arguments of Selection.SetCaretToPosition, when we need.

Solution: After a long road of "try&error", my best solution is, to replace the spaces with quotes. e.g. <Run Background="#FFB0E0E6">""</Run>.

On the one hand, this solves the problem with space-chars, on the other hand it is much more clear for the user, where to write. Additionally I added some code to place the caret between the 2 quotes, when the user enters the Run with cursor keys or clicks the wrong place.

koldomon
  • 1
  • 2