4

How do you scroll to the bottom of a TextBox for a UWP app?

With my transition to UWP, this has been one of the questions that hasn't been straight-forward.

I used to be able to use this:

textBox.SelectionStart = textBox.TextLength;
textBox.ScrollToCaret();

But, this doesn't work for UWP apps

Carlo Mendoza
  • 765
  • 6
  • 24

3 Answers3

6

Using the answer from https://code.msdn.microsoft.com/windowsapps/How-to-scroll-to-the-a8ea5867 sometimes caused lines to be deleted when scrolling up.

To fix that, try this:

private void ScrollToBottom(TextBox textBox)
{
    var grid = (Grid)VisualTreeHelper.GetChild(textBox, 0);
    for (var i = 0; i <= VisualTreeHelper.GetChildrenCount(grid) - 1; i++)
    {
        object obj = VisualTreeHelper.GetChild(grid, i);
        if (!(obj is ScrollViewer)) continue;
        ((ScrollViewer)obj).ChangeView(0.0f, ((ScrollViewer)obj).ExtentHeight, 1.0f, true);
        break;
    }
}

The main difference is this line:

((ScrollViewer)obj).ChangeView(0.0f, ((ScrollViewer)obj).ExtentHeight, 1.0f, true);

I also separated the method from the event handler, because I didn't want to necessarily scroll every time the text was changed.

Chris Sears
  • 311
  • 3
  • 2
  • 2
    This can also be used for ScrollToCaret. You split the string by the line terminator so you have the total line count, go through chars of the string until counting line endings until you hit the text SelectionStart position then divide the total lines by what row it was on. You can use that percent then to multiple against the ExtentHeight and boom, you're at the caret. – b.pell Apr 02 '19 at 17:39
5

If anyone needs to scroll to the bottom of a TextBox in UWP apps:

https://code.msdn.microsoft.com/windowsapps/How-to-scroll-to-the-a8ea5867

private void TextBox_TextChanged(object sender, TextChangedEventArgs e) 
{ 
    var grid = (Grid)VisualTreeHelper.GetChild(textBox1, 0); 
    for (var i = 0; i <= VisualTreeHelper.GetChildrenCount(grid) - 1; i++) 
        { 
            object obj = VisualTreeHelper.GetChild(grid, i); 
            if (!(obj is ScrollViewer)) continue; 
            ((ScrollViewer)obj).ChangeView(0.0f, ((ScrollViewer)obj).ExtentHeight, 1.0f); 
            break; 
        } 
    }
}

where textBox1 is the TextBox you want to scroll to the bottom.

Carlo Mendoza
  • 765
  • 6
  • 24
1

An equivalent to the previous answer in C++/CX:

using Windows::UI::Xaml::Media::VisualTreeHelper;
using Windows::UI::Xaml::Controls::Grid;
using Windows::UI::Xaml::Controls::ScrollViewer;
using Platform::Object;

void
MainPage::responseTextUpdated(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
{
    Grid^ grid = static_cast<Grid^>(VisualTreeHelper::GetChild(responseText, 0));
    for (int i = 0; i < VisualTreeHelper::GetChildrenCount(grid); ++i)
    {
        Object^ child = VisualTreeHelper::GetChild(grid, i);
        ScrollViewer^ scrollViewer = dynamic_cast<ScrollViewer^>(child);
        if (scrollViewer == nullptr) continue;

        double const horizontalOffset = 0;
        double const verticalOffset = scrollViewer->ExtentHeight;
        float const zoomFactor = 1;

        scrollViewer->ChangeView(horizontalOffset, verticalOffset, zoomFactor);
        break;
    }
}

Where responseText is TextBox^ responseText, the TextBox you want to scroll (probably the same as sender).

Jimmy Dee
  • 1,070
  • 1
  • 11
  • 17
  • Great answer, can't edit it to replace `responseText` with `(TextBox^)responseText` or `(TextBox^)sender` – rboy Mar 10 '23 at 10:32