1

我在我的 AvaloniaUI 应用程序中有这个设置:

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

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

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:'从无效线程调用'

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

4

1 回答 1

2

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

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

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

它现在就像那样工作。

于 2020-07-22T08:32:11.760 回答