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

WPF- Horizontal and Vertical position of a Run Element in a FlowDocument

有没有办法获取 FlowDocument 中 运行 元素的水平位置(像素)和垂直位置(像素)?

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

不会将其带到顶部,而只是在 运行 上调用 BringIntoView。保存对 运行.

的引用

回答您的问题
获取内容元素在文档中的位置所需的代码都是 .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,它应该位于视图的顶部。

可能晚了,但我仍然想分享我在 WPF 中的实现方式。 您需要一个偏移量才能这样做。

如上所说:流量给了你:

flow.ScrollToHome(); // Bottom

还给了:ScrollToVerticalOffset (get from Rect)

如果您有索引(char/line 的偏移量)- 您可以在保存的数据中找到它或使用 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得到Rect,Textpointer从Offset得到。 焦点只是为了确保将光标放在正确的位置。

有时当您跳转到多个偏移量时会发生此问题。 我建议在跳转之前触发 flow.ScrollToHome(); (因为这个 ScrollToVerticalOffset 从一开始就为真,而不是任何一行)