滚动到ScrollViewer的末尾的最佳方法

14

目前,我让我的代码在添加新项目时自动滚动到末尾的唯一方法是:

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>

代码:

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

这是常用的方法吗?我需要等待一段随机的时间吗?


嗨,你找到更好的解决方案了吗? - imslavko
await Dispatcher.Yield(DispatcherPriority.Input);会起作用吗? - springy76
9个回答

16

使用ActualHeight对我没有起作用(我还没有搞清楚原因)- 但是像这样使用ScrollableHeight就可以解决问题:

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

15

对于Windows Phone 8.1,我使用这个:

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

同样在Windows 8.1上运行良好。 - tec-goblin
1
这是在UWP应用程序中执行此操作的正确方法。如果您使用ScrollToVerticalOffset,编译器将会给出以下提示:'ScrollViewer.ScrollToVerticalOffset(double)'已过时:'ScrollToVerticalOffset可能在Windows 8.1之后的版本中被更改或不可用。请改用ChangeView。' - Adrian K

3

在我看来,最好的选择是以下方式继承自ScrollViewer:

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

以及XAML

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

然后,您可以直接在XAML中使用新类,无需额外的代码,这对于使用“纯”MVVM代码特别有用。


2

2

除了JavaScript之外,在任何语言中,没有随机异步性是解决问题的正确方法... 它总是会有那种“代码气味”,您知道吗?

正确的做法是通过调用ScrollViewer.Measure(Size)同步地强制刷新ScrollViewer的度量,以包括新添加的子元素。

重新测量后,ScrollableHeight将是正确的值,您可以像往常一样使用它。

像这样:

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

我们在这里使用的SizeRenderSize,在一些极端情况下可能不正确,但它非常接近完美地适合我们的目的。你也可以在Measure(Size)中使用任意大的Size来获得相同的效果。无论哪种方法对你的解决方案最好,希望这能帮到你-ck。

.Measure 在 WinRT 中可用,但在 WP8.1 中不可用(有时会滚动,有时不会)。 chatViewContent.UpdateLayout(); chatViewContent.ChangeView(null, chatViewContent.ScrollableHeight, null); 在 WP8.1 中可用 [未在 WinRT 中尝试,可能在两者中都可用]。 - Rui

2

对于WindowsPhone通用应用程序,您可以使用以下方法:

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

0

0
我使用了以下内容:
ScrollViewer viewer = GetScrollViewer();
if (viewer != null)
{
    viewer.ScrollToVerticalOffset(viewer.ActualHeight);
}

另一种解决方案是将项目放入一个ListBox中,并使用ScrollIntoView方法。

0

ScrollViewer.ScrollToVerticalOffset(ScrollViewer.ActualHeight) 应该是有效的,但如果你的代码刚刚更新了滚动视图的内容,你可能需要在滚动之前调用 ScrollViewer.UpdateLayout(),以便 ScrollViewer.ActualHeight 是最新的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接