检测FlowDocument更改和滚动

Jas*_*aty 5 wpf scroll flowdocument

我想检测(最好通过一个事件)什么时候添加,更改等任何内容FlowDocument,当它出现时我想让FlowDocumentScrollViewer显示FlowDocument自动滚动到结尾.

Ray*_*rns 8

您可以FlowDocument通过创建文本范围并监视更改来检测更改.滚动到底部更加困难,因为你必须找到ScrollViewer.同样对于性能,您不希望在每次更改时重做所有滚动计算,因此您应该使用DispatcherOperations.

总而言之,这段代码应该可以解决问题:

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();
    });
};
Run Code Online (Sandbox Code Playgroud)

其中FindFirstVisualDescendantOfType,使用一个简单的深度优先前缀搜索所述视觉树VisualTreeHelper.GetChildrenCount()VisualTreeHelper.GetChild()和返回第一视觉发现指定类型的.

请注意,为了完全通用,我不会在代码顶部预先计算scrollViewer,因为它FlowDocumentScrollViewer的模板可以更改.如果不发生这种情况,可以通过.ApplyTemplate()在注册事件处理程序之前调用FlowDocumentScrollViewer然后计算来加速此代码scrollViewer:

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();
    });
};
Run Code Online (Sandbox Code Playgroud)

请注意,我们不能简单地调用scrollViewer.GetTemplateChild("PART_ContentHost")和跳过可视树搜索,因为GetTemplateChild它受到保护.