问题描述
我想检测(最好通过事件)何时在 FlowDocument
中添加、更改等任何内容,以及何时我想导致 FlowDocumentScrollViewer
显示 FlowDocument
以自动滚动到末尾.
I want to detect (preferably through an event) when any content is added, changed, etc. in a FlowDocument
and when it does I want to cause a FlowDocumentScrollViewer
displaying the FlowDocument
to automatically scroll to the end.
推荐答案
您可以通过创建文本范围并监视其更改来检测 FlowDocument
中的更改.滚动到底部比较困难,因为您必须找到 ScrollViewer
.此外,为了提高性能,您不想在每次更改时重做所有滚动计算,因此您应该使用 DispatcherOperations
.
You can detect changes in the FlowDocument
by creating a text range and monitoring it for changes. Scrolling to the bottom is more difficult because you have to find the ScrollViewer
. Also for performance you don't want redo all the scrolling calculations on every change, so you should use DispatcherOperations
.
综合起来,这段代码应该可以解决问题:
Putting it all together, this code should do the trick:
var range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
object operation = null;
range.Changed += (obj, e) =>
{
if(operation==null)
operation = Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
operation = null;
var scrollViewer = FindFirstVisualDescendantOfType<ScrollViewer>(flowDocument);
scrollViewer.ScrollToBottom();
});
};
其中 FindFirstVisualDescendantOfType
是使用 VisualTreeHelper.GetChildrenCount()
和 VisualTreeHelper.GetChild()
对可视化树进行简单的深度优先前缀搜索并返回找到的第一个指定类型的 Visual.
where FindFirstVisualDescendantOfType
is a simple depth-first prefix search of the visual tree using VisualTreeHelper.GetChildrenCount()
and VisualTreeHelper.GetChild()
and returning the first Visual found of the specified type.
请注意,为了全面起见,我不会在代码顶部预先计算 scrollViewer,因为 FlowDocumentScrollViewer
的模板可以更改.如果这不会发生,可以通过在 FlowDocumentScrollViewer
上调用 .ApplyTemplate()
并在事件之前计算 scrollViewer
来加速此代码处理程序已注册:
Note that for full generality I don't precompute scrollViewer at the top of the code because the FlowDocumentScrollViewer
's template can change. If this won't happen, this code can be speeded up by calling .ApplyTemplate()
on the FlowDocumentScrollViewer
and then computing scrollViewer
before the event handler is registered:
var range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
object operation = null;
flowDocument.ApplyTemplate();
var scrollViewer = FindFirstVisualDescendantOfType<ScrollViewer>(flowDocument);
range.Changed += (obj, e) =>
{
if(operation==null)
operation = Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
operation = null;
scrollViewer.ScrollToBottom();
});
};
请注意,我们不能简单地调用 scrollViewer.GetTemplateChild("PART_ContentHost")
并跳过可视化树搜索,因为 GetTemplateChild
是受保护的.
Note that we cannot simply call scrollViewer.GetTemplateChild("PART_ContentHost")
and skip the visual tree search because GetTemplateChild
is protected.
这篇关于检测 FlowDocument 更改和滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!