在我的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线程调用,因为我得到了一个异常:
System.InvalidOperationException:“从无效线程调用”
我的问题是,每当我通过ScrollViewer更新TextBlocks Text属性时,我如何自动将TextBlocks保存到最后?
发布于 2020-07-22 08:32:11
好吧,我想出来了,但把这个留在这里作为参考。
为了从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);
它现在就是这样工作的。
https://stackoverflow.com/questions/63002134
复制相似问题