使用 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);
现在就是这样。
我的 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);
现在就是这样。