Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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;

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

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)

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

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.