jumpcutking
jumpcutking

Reputation: 620

How do I mark the cursor to stick in the character position it was at? (WPF RichTextBox)

I am using a WPF richtextbox to create a syntax highlighter for code provided in a textbox. I want to have it automatically adjust the rich textbox as I am typing, using a thread timer I reset the contents of the rich textbox. I am trying to keep the cursor where it is suppose to be. I don't loose any text characters during the parse (except line breaks). I don't know how to keep the caret position where the user has left it in the text. It defaults to the end of the document.

I attempt to store the current caret position in the text and then set it to the document after I make my changes, however the error I receive is "Cannot set CaretPosition to be outside of RichTextBox." So I set the caret position to the bottom of the document.

WPF, VB.net, .net Framework 4.0

Here is the code.

Public Sub FormatText()

    If IsNothing(rtfContent.Document) Then
        Exit Sub
    End If

    Me.rtfContent.IsEnabled = False
    Me.rtfContent.Refresh()
    Me.Refresh()

    System.Threading.Thread.Sleep(50)

    Dim curRange As TextRange = New TextRange(rtfContent.Document.ContentStart, rtfContent.CaretPosition)

    Dim caretBefore As TextPointer = rtfContent.CaretPosition
    caretBefore = New TextRange(caretBefore, caretBefore.DocumentEnd).Start

    Dim caretBeforeOffset As Integer = rtfContent.Document.ContentStart.GetOffsetToPosition(caretBefore)

    Dim docRange As TextRange = New TextRange(rtfContent.Document.ContentStart, rtfContent.Document.ContentEnd)
    docRange.ClearAllProperties()

    Dim myText As String = docRange.Text
    Dim Lines As List(Of String) = Split(myText, vbCrLf).ToList
    Dim MyBlocks As New List(Of Block)
    Dim count As Integer = 1
    MyVars.Clear()
    myText = ""

    For Each Line In Lines
        If count = Lines.Count Then
            Exit For
        End If

        If Mid(Line, 1, 1) = "$" Then
            Dim words As String() = Split(Line, " ", 2)
            MyVars.Add(words(0))
            myText &= "<Paragraph Margin=""0,0,0,0"" Padding=""0,0,0,2"">" & Line & "</Paragraph>"
        ElseIf Mid(Line, 1, 1) = "#" Then
            myText &= "<Paragraph Margin=""0,0,0,0"" Padding=""0,0,0,2""><Run Foreground=""#FFFFA500"">" & Line & "</Run></Paragraph>"
        Else
            myText &= "<Paragraph Margin=""0,0,0,0"" Padding=""0,0,0,2"">" & Line & "</Paragraph>"
        End If

        count += 1
    Next

    myText = Regex.Replace(myText, "\$(\w*)", "<Run Foreground=""#FFFF0000"">$$$1</Run>")

    For Each var In MyVars
        myText = Regex.Replace(myText, "<Run Foreground=""#FFFF0000"">\" & var & "</Run>", "<Run Foreground=""#FF32CD32"">" & var & "</Run>")
    Next

    myText = myText.Replace("copy", "<Run Foreground=""#FF87CEFA"">copy</Run>")
    myText = myText.Replace("delete", "<Run Foreground=""#FF87CEFA"">delete</Run>")
    myText = myText.Replace("output", "<Run Foreground=""#FF87CEFA"">output</Run>")
    myText = myText.Replace("clear", "<Run Foreground=""#FF87CEFA"">clear</Run>")

    myText = "<FlowDocument PagePadding=""5,0,5,0"" AllowDrop=""True"" NumberSubstitution.CultureSource=""User"" xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">" & myText & "</FlowDocument>"

    Me.rtfContent.Document.Blocks.Clear()
    Me.rtfContent.Document = TryCast(XamlReader.Parse(myText), FlowDocument)

    caretBefore = caretBefore.DocumentStart.GetPositionAtOffset(caretBeforeOffset, LogicalDirection.Forward)

    Try
        Me.rtfContent.CaretPosition = caretBefore
    Catch
        Me.rtfContent.CaretPosition = rtfContent.Document.ContentEnd
    End Try

    Me.rtfContent.IsEnabled = True
    Me.rtfContent.Refresh()
    Me.Refresh()

End Sub

Upvotes: 1

Views: 1334

Answers (1)

Yasser Sobhdel
Yasser Sobhdel

Reputation: 641

I have an idea which might help. Does Point GetPositionFromCharIndex(int index), PointToClient and PointToScreen functions help? You can store which char index the mouse cursor was over and after generating the code put it back in the mentioned position. You can find usage of those functions here.

Upvotes: 1

Related Questions