10
votes

How to set caret/cursor position in RichTextBox in WPF?

I use the code in MSDN CaretPosition but it seems the cursor can't be set?

// Create a new FlowDocument, and add 3 paragraphs.
FlowDocument flowDoc = new FlowDocument();
flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 1"))); 
flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 2"))); 
flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 3")));
// Set the FlowDocument to be the content for a new RichTextBox.
RichTextBox rtb = new RichTextBox(flowDoc);

// Get the current caret position.
TextPointer caretPos = rtb.CaretPosition;

// Set the TextPointer to the end of the current document.
caretPos = caretPos.DocumentEnd;

// Specify the new caret position at the end of the current document.
rtb.CaretPosition = caretPos;
2

2 Answers

20
votes

How to set caret/cursor position in RichTextBox in WPF?

Assuming thatrtb is the name of your RichTextBox, with different Blocks and Inlines, you can set the Caret at the beginning of the document by:

rtb.CaretPosition = rtb.CaretPosition.DocumentStart;

or at its end:

rtb.CaretPosition = rtb.CaretPosition.DocumentEnd;

On the other hand, assuming that you have a specific Paragraph or Block, such as:

Block blk = rtb.Document.Blocks.ElementAt(1);

You can set caret to its start

rtb.CaretPosition = blk.ContentStart;

or its end

rtb.CaretPosition = blk.ContentEnd;

or if you have a specific Inline such as

Run r = ((Paragraph)rtb.Document.Blocks.ElementAt(0)).Inlines.ElementAt(1) as Run;

You can also use

rtb.CaretPosition = r.ContentStart;
rtb.CaretPosition = r.ContentEnd;

Of course, if you are working with Complex paragraph with both right-to-left and left-to-right text, you might need to consider

rtb.CaretPosition = blk.ElementStart;
rtb.CaretPosition = blk.ElementEnd;

Also note different methods implemented in a TextPointer, which you can use to reach different parts of the document/Blocks/Inlines:

rtb.CaretPosition = rtb.CaretPosition.GetLineStartPosition(0);
rtb.CaretPosition = rtb.CaretPosition.GetPositionAtOffset(2);

See the link for more methods and more information.

At the end, you might want to use BringIntoView method implemented in a Block or Inline:

blk.BringIntoView();
r.BringIntoView();

and also setting the keyboard focus, to see the blinking of the Caret:

Keyboard.Focus(rtb);
3
votes

Remember to Set focus so that the cursor will appear in the RichTextBox:

// Create a new FlowDocument, and add 3 paragraphs.
FlowDocument flowDoc = new FlowDocument();
flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 1"))); 
flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 2"))); 
flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 3")));
// Set the FlowDocument to be the content for a new RichTextBox.
RichTextBox rtb = new RichTextBox(flowDoc);

//****SET FOCUS****
rtb.Focus();

// Get the current caret position.
TextPointer caretPos = rtb.CaretPosition;
// Set the TextPointer to the end of the current document.
caretPos = caretPos.DocumentEnd;
// Specify the new caret position at the end of the current document.
rtb.CaretPosition = caretPos;

.

In addition to Setting to Document End, You can use GetPositionAtOffset to set caretPos backward / forward and amount of displacement you want to move:

int displacement = 8;

// Set the TextPointer 8 displacement backward.
caretPos = caretPos.GetPositionAtOffset(displacement, LogicalDirection.Backward);

.

Example, you can paste it to the Constructor of an Empty Window to test:

    public RichTbxFlowDocumentTest()
    {
        InitializeComponent();

        // Create a new FlowDocument, and add 3 paragraphs.
        FlowDocument flowDoc = new FlowDocument();
        flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 1")));
        flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 2")));
        flowDoc.Blocks.Add(new Paragraph(new Run("Paragraph 3")));
        // Set the FlowDocument to be the content for a new RichTextBox.
        RichTextBox rtb = new RichTextBox(flowDoc);

        //Add RichTextBox and Button with setting cursor method to a new StackPanel
        StackPanel s = new StackPanel();
        Button button = new Button() { Content = "Set Cursor Pos" };
        button.Click += (sender, e) =>
        {
            //SET FOCUS
            rtb.Focus();

            // Get the current caret position.
            TextPointer caretPos = rtb.CaretPosition;

            //Set amount of displacement
            int displacement = 6;

            // Set the TextPointer 6 displacement backward
            caretPos = caretPos.GetPositionAtOffset(displacement, LogicalDirection.Backward);

            // Specify the new caret position to RichTextBox
            rtb.CaretPosition = caretPos;
        };
        s.Children.Add(button);
        s.Children.Add(rtb);
        this.Content = s;
    }
}

.

Result:

(I move the window in the middle to prevent afterimage)

enter image description here

.

Other Supplement:

If you want to move RichTextBox caret up or down one line, you can see https://social.msdn.microsoft.com/Forums/vstudio/en-US/8c34e7b1-91ed-4b11-979d-d18b28a71f6f/how-do-you-move-richtextbox-caret-up-or-down-one-line?forum=wpf

myRichTextBox.Focus();
EditingCommands.MoveUpByLine.Execute(null, myRichTextBox);