Search code examples
wpfscrolltextboxmultilinecaret

WPF scroll multiline textbox to caret position


today I'm searching for a way to scroll a multiline, dynamically sized textbox.

I want to scroll to the Caret and don't find any helpful informations at the internet.

After trying many things i know how to scroll to the end of a line, but not how to scroll to the caret. The scroll to the right line is already implemented, but the horizontal scroll part is already missing.

 private void txtText_PreviewKeyDown(object sender, KeyEventArgs e)
 {
        if (e.Key == Key.Down || e.Key == Key.Up)
        {
            var CurrentLineIndex = txtText.GetLineIndexFromCharacterIndex(((TextBox)sender).SelectionStart);
            txtText.ScrollToLine(CurrentLineIndex);
        }
       
 }

This is my current code, which does scrolling to the right line for me.

Tryed to do something simular for the horizontal scrolling:

var rect = ((TextBox)sender).GetRectFromCharacterIndex(((TextBox)sender).CaretIndex);
txtText.ScrollToHorizontalOffset(Math.Max((txtText.HorizontalOffset + rect.Right - (txtText.ActualWidth - 40)), 0.0));

But it doesn't work like expected, it scrolls not to the horizontal caret position.

Think, i had to discribe it better:

if i move the caret with the left or right arrow, it will work fine without implementing anything.

It doesn't work if i do this:

Move from one line to another. Sometimes one of these lines is longer or shorter than another and at this case i had to scroll to the caret position.

Example:

Line1 is longer than line2

I navigate with the key "end" at the keyboard to the end of line1.

Then i navigate to to line2.

It all works correctly, the caret jumps to the end of line2 and it will scrolls automatically into visibile area.

But if i go back from line2 to line1 the caret is position right at the end of line1. But it scrolls not to the end of line1.


Solution

  • the problem was that i used a Style template and forgot a necessary thing:

    to pass

     ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}" 
    

    to the ScrollContentPresenter.

    After doing this, the standard behaviour will work well!