Nick Banks
Nick Banks

Reputation: 4408

Best Way to Scroll to End of ScrollViewer

Currently, the only way I have gotten my code to auto scroll to the end when I add a new item is the following:

XAML:

<ScrollViewer x:Name="chatViewScroller" HorizontalAlignment="Left" Height="201" Margin="0,32,0,0" VerticalAlignment="Top" Width="475" Background="#7FFFFFFF">
    <StackPanel x:Name="chatViewContent" />
</ScrollViewer>

Code:

                chatViewContent.Children.Add(
                    new TextBlock() {
                        Text = text,
                        FontSize = 18,
                        TextWrapping = Windows.UI.Xaml.TextWrapping.Wrap,
                        Margin = new Thickness(10, 3, 10, 0),
                        Foreground = new Windows.UI.Xaml.Media.SolidColorBrush(
                            isServerMessage ? Windows.UI.Colors.Purple : Windows.UI.Colors.Black)
                    });
                await Task.Delay(10);
                chatViewScroller.ScrollToVerticalOffset(chatViewScroller.ScrollableHeight);

Is this the accepted way of doing it? Do I have to wait for some random period of time?

Upvotes: 14

Views: 18933

Answers (9)

Jacek Plesnar
Jacek Plesnar

Reputation: 505

In my opinion best option is to inherit from ScrollViewer in following way:

public partial class AutoScrollViewer
{        
    public AutoScrollViewer()
    {
        InitializeComponent();
        this.SizeChanged += (sender, args) => this.ScrollToBottom();
    }
}

and XAML

<ScrollViewer x:Class="AutoScrollViewer"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</ScrollViewer>

Then you can use directly in XAML the new class without additional code behind which is usefull especailly when you have "pure" MVVM code.

Upvotes: 3

Don H
Don H

Reputation: 677

For WindowsPhone Universal app you can use:

 var scrollableHeight = ScrollViewer.ScrollableHeight;
        if (scrollableHeight > 0)
        {
           ScrollViewer.ScrollToVerticalOffset(scrollableHeight);
        }

Upvotes: 2

Tealc Wu
Tealc Wu

Reputation: 504

For Windows Phone 8.0, you can use

MyScrollViewer.ScrollToVerticalOffset(MyScrollViewer.ExtentHeight - MyScrollViewer.ViewportHeight);

Please also refer to http://msdn.microsoft.com/en-us/library/windows/apps/system.windows.controls.scrollviewer.verticaloffset(v=vs.105).aspx

Upvotes: 0

Aaron Campbell
Aaron Campbell

Reputation: 602

If you are working with .NET 3.0 or later, you can use ScrollViewer.ScrollToBottom().

MSDN doc: http://msdn.microsoft.com/en-us/library/system.windows.controls.scrollviewer.scrolltobottom(v=vs.110).aspx

Upvotes: 2

A.J.Bauer
A.J.Bauer

Reputation: 3001

For Windows Phone 8.1 I use this:

MyScrollViewer.ChangeView(0.0f, double.MaxValue, 1.0f);

Upvotes: 15

RiaanDP
RiaanDP

Reputation: 1212

Using ActualHeight did not work for me (I have yet to figure out why) - but using ScrollableHeight like this did the the trick:

// adding item to ItemsControl...
// ...
_scrollViewer.UpdateLayout();
_scrollViewer.ScrollToVerticalOffset(_scrollViewer.ScrollableHeight);

Upvotes: 16

ckozl
ckozl

Reputation: 6761

no random asynchronicity is never the answer to anything in any language except maybe JavaScript... it just always has that "code smell" you know?

the proper way to do this is to force a "refresh" of the measure of the ScrollViewer synchronously to include the newly added children by calling ScrollViewer.Measure(Size)

after you "re-measure" the ScrollableHeight will be the proper value and you can use it as you normally would..

like this:

    private void AddMessage(string text, Color color)
    {
        var message = new TextBlock
        {
            Text = text,
            FontSize = 18,
            TextWrapping = TextWrapping.Wrap,
            Margin = new Thickness(10, 3, 10, 0),
            Foreground = new SolidColorBrush(color),
        };

        chatViewContent.Children.Add(message);

        chatViewScroller.Measure(chatViewScroller.RenderSize);
        chatViewScroller.ScrollToVerticalOffset(chatViewScroller.ScrollableHeight);
    }

the Size we are using here is the RenderSize which could technically be incorrect in some extreme edge cases, but it is pretty close to perfectly ideal for our purposes. you could also technically use an arbitrarily large Size for the Measure(Size) and get the same effect. whatever works best for your solution, hope this helps -ck

Upvotes: 2

BigScary
BigScary

Reputation: 560

ScrollViewer.ScrollToVerticalOffset(ScrollViewer.ActualHeight) should work, but if your code has just now updated the content of the scroll viewer, you may want to call ScrollViewer.UpdateLayout() before scrolling, so that ScrollViewer.ActualHeight will be up to date.

Upvotes: 0

Shawn Kendrot
Shawn Kendrot

Reputation: 12465

I've used the following:

ScrollViewer viewer = GetScrollViewer();
if (viewer != null)
{
    viewer.ScrollToVerticalOffset(viewer.ActualHeight);
}

Another solution is to put the items into a ListBox and use the ScrollIntoView method

Upvotes: 0

Related Questions