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
中,过程有点复杂。
加载控件时,注册 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,它应该位于视图的顶部。
可能晚了,但我仍然想分享我在 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 从一开始就为真,而不是任何一行)
有没有办法获取 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
中,过程有点复杂。加载控件时,注册 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,它应该位于视图的顶部。
可能晚了,但我仍然想分享我在 WPF 中的实现方式。 您需要一个偏移量才能这样做。
如上所说:流量给了你:
flow.ScrollToHome(); // Bottom
还给了:ScrollToVerticalOffset (get from Rect)
如果您有索引(char/line 的偏移量)- 您可以在保存的数据中找到它或使用 flow.Selection.Start/End
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 从一开始就为真,而不是任何一行)