流文档中运行元素的水平和垂直位置
本文关键字:水平 垂直 位置 元素 文档 运行 | 更新日期: 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
中,这个过程稍微复杂一些。-
当控件加载时,注册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(); }
-
在处理程序中,深入查找
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; } } } }
-
一旦你有了
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从一开始就为真,而不是任何一行)