使用 DataBinding 时如何自动滚动 AvaloniaUI ScrollViewer?

How to autoscroll AvaloniaUI ScrollViewer when using DataBinding?

我的 AvaloniaUI 应用程序中有此设置:

<ScrollViewer VerticalScrollBarVisibility="Auto"
              AllowAutoHide="True"
              Name="MessageLogScrollViewer">
  <TextBlock HorizontalAlignment="Stretch"
             VerticalAlignment="Stretch"
             TextWrapping="NoWrap"
             Text="{Binding ReceivedMessages}"></TextBlock>
</ScrollViewer>

TextBlock 基本上显示日志消息,我希望它自动滚动到底部,当我将新行附加到绑定到文本 属性 的字符串时。

ScrollViewer 有一个名为 ScrollToEnd() 的方法,每当我更新文本时都需要调用该方法。所以我试着在我的代码中定义一个函数,如下所示:

private ScrollViewer messageLogScrollViewer;    
public MainWindow()
{
    InitializeComponent();

    DataContext = new MainWindowViewModel(this);
    messageLogScrollViewer = this.FindControl<ScrollViewer>("MessageLogScrollViewer");
}

...

public void ScrollTextToEnd()
{
    messageLogScrollViewer.ScrollToEnd();
}

然后我尝试从我的 ViewModel 调用该函数:

private string receivedMessages = string.Empty;
public string ReceivedMessages
{
    get => receivedMessages;
    set => this.RaiseAndSetIfChanged(ref receivedMessages, value);
}

...

private MainWindow _window;
public MainWindowViewModel(MainWindow window)
{
    _window = window;
}

...

ReceivedMessage += "\n";
ReceivedMessages += ReceivedMessage;
_window.ScrollTextToEnd(); // Does not work.

但不幸的是,这个 ScrollToEnd() 函数需要从 UI-Thread 调用,因为我得到一个异常:

System.InvalidOperationException: 'Call from invalid thread'

我的问题是,每当我通过 DataBinding 更新 TextBlocks 文本 属性 时,如何将我的 ScrollViewer 自动滚动到最后?

好的,我想通了,但留在这里以供参考。

为了从 UI-线程上的另一个线程执行函数,需要调用

Dispatcher.UIThread.InvokeAsync(_window.ScrollTextToEnd);

但这只滚动到倒数第二行,所以当我调用 ScrollTextToEnd() 时,控件似乎还没有更新。因此,我在更新文本和调用滚动函数之间添加了一个短暂的超时

ReceivedMessages += ReceivedMessage;
// A short timeout is needed, so that the scroll viewer will scroll to the new end of its content.
Thread.Sleep(10);
Dispatcher.UIThread.InvokeAsync(_window.ScrollTextToEnd);

现在就是这样。