流文档中运行元素的水平和垂直位置

本文关键字:水平 垂直 位置 元素 文档 运行 | 更新日期: 2023-09-27 17:50:55

在FlowDocument中是否可以获得Run元素的水平位置(像素)和垂直位置(像素)?

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

流文档中运行元素的水平和垂直位置

回答你的问题
获取文档中内容元素位置所需的代码都是. net内部的,没有公开。您需要访问一个IContentHost实现,而内置的文档查看器并没有公开它。所以,没有支持的方法来做你所要求的。

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

在应用程序中有多种显示FlowDocument的方式。如何处理滚动取决于您使用哪个控件来显示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,它应该在视图的顶部

不会把它带到顶部,而是在运行时调用BringIntoView。保存引用到Run.

这可能有点晚了,但我仍然想分享我在WPF中做的方法。你需要一个偏移量。

如上所述:Flow给了你:

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中获取Rect,从TextPointer中获取Offset。焦点只是为了确保光标放置在正确的位置。

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