WPF- FlowDocument中Run元素的水平和垂直位置

时间:2015-05-27 12:09:59

标签: c# wpf flowdocument

无论如何要获取FlowDocument中Run元素的水平位置(像素)和垂直位置(像素)?

编辑: 我需要做的就是滚动到该位置并使其成为FlowDocument的顶行。

3 个答案:

答案 0 :(得分:2)

回答您的问题
获取文档中内容元素位置所需的代码都是.NET内部的,而不是公开的。您需要访问IContentHost实现,内置文档查看器不会公开显示该实现。所以,没有支持的方式来做你要求的。

解决您的实际问题
有一种方法可以实现将元素滚动到视图顶部所需的结果。你想要做的是滚动到文档的末尾,然后在你想要的顶部元素上调用BringIntoView

应用程序中有multiple ways a FlowDocument can be displayed。如何处理滚动取决于您使用哪个控件来呈现FlowDocument

  • RichTextBox中,使用ScrollToEnd方法。
  • FlowDocumentScrollViewer中,您需要获取其内部ScrollViewer并在其上调用ScrollToBottom。 (您必须等到控件加载后再从中获取模板部分。)

    private void MyControl_Loaded(object sender, RoutedEventArgs e)
    {
        mScrollViewer = mViewer.Template.FindName("PART_ContentHost", mViewer) as ScrollViewer;
    }
    
  • FlowDocumentReader中,这个过程有点复杂。

    1. 加载控件后,注册ViewingMode属性的更改并运行处理程序一次以考虑起始值:

      private void MyControl_Loaded(object sender, RoutedEventArgs e)
      {
          var descriptor = DependencyPropertyDescriptor.FromProperty(FlowDocumentReader.ViewingModeProperty, typeof(FlowDocumentReader));
          descriptor.AddValueChanged(mReader, (s, a) => Reader_ViewModeChanged());
          Reader_ViewModeChanged();
      }
      
    2. 在处理程序中,深入查找ScrollViewer。它仅在ViewingMode设置为Scroll时才会出现:

      private void Reader_ViewModeChanged()
      {
          mScrollViewer = null;
          if (mReader.ViewingMode == FlowDocumentReaderViewingMode.Scroll)
          {
              var contentHost = mReader.Template.FindName("PART_ContentHost", mReader) as DependencyObject;
              if (contentHost != null && VisualTreeHelper.GetChildrenCount(contentHost) > 0)
              {
                  var documentScrollViewer = VisualTreeHelper.GetChild(contentHost, 0) as FlowDocumentScrollViewer;
                  if (documentScrollViewer != null)
                  {
                      documentScrollViewer.ApplyTemplate();
                      mScrollViewer = documentScrollViewer.Template.FindName("PART_ContentHost", documentScrollViewer) as ScrollViewer;
                  }
              }
          }
      }
      
    3. 获得ScrollViewer后,您可以在需要时致电ScrollToBottom

现在,滚动到文档的底部,然后在Run上调用BringIntoView,它应位于视图的顶部。

答案 1 :(得分:1)

不会将其置于顶部,只需在运行时调用BringIntoView即可。保存对Run的引用。

答案 2 :(得分:0)

可能已经晚了,但是我仍然想分享我在WPF中进行DID的方式。 您需要一个偏移量。

如上所述:流程给了你

flow.ScrollToHome(); // Bottom

但也给出了:ScrollToVerticalOffset (get from Rect)

如果您有索引(字符/行的偏移量)-您可以在保存的数据中找到它,或者使用flow.Selection.Start/End获取TextPointer

TextPointer t_st = flow.Selection.Start;
double offset = flow.Document.ContentStart.GetOffsetToPosition(t_st);

    private void gotoOffset(double offset)
    {
        TextPointer myTextPointer1 = flow.Document.ContentStart.GetPositionAtOffset((int)offset);
        flow.Selection.Select(myTextPointer1, myTextPointer1);
        flow.Focus();
        Rect screenPos2 = myTextPointer1.GetCharacterRect(LogicalDirection.Forward);
        double offset2 = screenPos2.Top;
        Thread.Sleep(100);

        flow.ScrollToVerticalOffset(offset2);
        flow.Focus();
    }

作为上面的代码,我们从TextPointer,Textpointer获取Rect,并从Offset获取。 焦点只是为了确保将光标放置在正确的位置。

有时候,当您跳到许多偏移时,就会发生此问题。 我建议在跳动之前触发flow.ScrollToHome();(因为从头开始,此ScrollToVerticalOffset为true,所以没有一行)