检测的FlowDocument变化和Scroll(Detect FlowDocument Chang

2019-09-03 05:18发布

我想检测(优选通过事件)时的任何内容的增加,改变等。在一个FlowDocument和当它欲引起FlowDocumentScrollViewer显示FlowDocument自动滚动到最后。

Answer 1:

您可以检测在变化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();
    });
};

其中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();
    });
};

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



Answer 2:

您是否使用一个RichTextBox做编辑? 如果是这样,你就应该能够挂钩的TextChanged事件 ,然后调用该ScrollToVerticalOffset方法与价值的ViewportHeight财产 。



Answer 3:

挂钩的TextChanged事件后,你可以简单地使用:

// Showing Last Block
YourReader.Document.Blocks.LastBlock.BringIntoView();

// Or.. showing the last Inline
(YourReader.Document.Blocks.LastBlock as Paragraph).Inlines.LastInline.BringIntoView();

这适用于FlowDocumentPageViewer,并在FlowDocumentReader(配页ViewingModes),对于FlowDocumentScrollViewer你应该使用可视化树如前所述

public static ScrollViewer FindScroll(Visual visual)
        {
            if (visual is ScrollViewer)
                return visual as ScrollViewer;

            ScrollViewer searchChiled = null;
            DependencyObject chiled;

            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
            {
                chiled = VisualTreeHelper.GetChild(visual, i);
                if (chiled is Visual)
                    searchChiled = FindScroll(chiled as Visual);
                if (searchChiled != null)
                    return searchChiled;
            }

            return null;
        }

ScrollViewer scroller = FindScroll(YourReader as Visual);
if (scroller != null) 
   (scroller as ScrollViewer).ScrollToBottom();


Answer 4:

您可以使用下面的扩展方法来获得内滚动查看器:

public static class FlowDocumentScrollViewerExtensions
{
  public static ScrollViewer GetScrollViewer(this FlowDocumentScrollViewer element) {
    if (element == null) {
      throw new ArgumentNullException(nameof(element));
    }

    return element.Template?.FindName("PART_ContentHost", element) as ScrollViewer;
  }
}

此外,您可以使用这些扩展方法中添加内容之前检查滚动位置的ScrollViewer本身(如果你想滚动-only-如果滚动观众已经在最后为例):

public static class ScrollViewerExtensions
{
  public static bool IsAtHome(this ScrollViewer element) {
    if (element == null) {
      throw new ArgumentNullException(nameof(element));
    }

    return element.VerticalOffset <= 0;
  }

  public static bool IsAtEnd(this ScrollViewer element) {
    if (element == null) {
      throw new ArgumentNullException(nameof(element));
    }

    return element.VerticalOffset >= element.ScrollableHeight;
  }
}

后来才调用scrollViewer.ScrollToEnd()为例。



文章来源: Detect FlowDocument Change and Scroll