本文介绍了检测 FlowDocument 更改和滚动的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想检测(最好通过事件)何时在 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 更改和滚动的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-23 09:20