我想检测(优选通过事件)时的任何内容的增加,改变等。在一个FlowDocument
和当它欲引起FlowDocumentScrollViewer
显示FlowDocument
自动滚动到最后。
Answer 1:
您可以检测在变化FlowDocument
通过创建一个文本范围和监视它的变化。 滚动至底部是比较困难的,因为你必须要找到ScrollViewer
。 当然性能也是不希望重做上每一次改变所有的滚动计算,所以你应该使用DispatcherOperations
。
综合起来,这些代码应该做的伎俩:
var range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
object operation = null;
range.Changed += (obj, e) =>
{
if(operation==null)
operation = Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
operation = null;
var scrollViewer = FindFirstVisualDescendantOfType<ScrollViewer>(flowDocument);
scrollViewer.ScrollToBottom();
});
};
其中FindFirstVisualDescendantOfType
是使用一个简单的深度优先前缀搜索所述视觉树的VisualTreeHelper.GetChildrenCount()
和VisualTreeHelper.GetChild()
并返回所述第一视觉发现指定类型的。
请注意,对于一些通用化我不会在代码的顶部预先计算的ScrollViewer因为FlowDocumentScrollViewer
的模板可以改变。 如果这不会发生,这个代码可以通过调用可以加快.ApplyTemplate()
在FlowDocumentScrollViewer
,然后计算scrollViewer
事件处理程序注册之前:
var range = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
object operation = null;
flowDocument.ApplyTemplate();
var scrollViewer = FindFirstVisualDescendantOfType<ScrollViewer>(flowDocument);
range.Changed += (obj, e) =>
{
if(operation==null)
operation = Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
operation = null;
scrollViewer.ScrollToBottom();
});
};
请注意,我们不能简单地调用scrollViewer.GetTemplateChild("PART_ContentHost")
跳过视觉树搜索,因为GetTemplateChild
保护。
Answer 2:
您是否使用一个RichTextBox做编辑? 如果是这样,你就应该能够挂钩的TextChanged
事件 ,然后调用该ScrollToVerticalOffset
方法与价值的ViewportHeight
财产 。
Answer 3:
挂钩的TextChanged事件后,你可以简单地使用:
// Showing Last Block
YourReader.Document.Blocks.LastBlock.BringIntoView();
// Or.. showing the last Inline
(YourReader.Document.Blocks.LastBlock as Paragraph).Inlines.LastInline.BringIntoView();
这适用于FlowDocumentPageViewer,并在FlowDocumentReader(配页ViewingModes),对于FlowDocumentScrollViewer你应该使用可视化树如前所述
public static ScrollViewer FindScroll(Visual visual)
{
if (visual is ScrollViewer)
return visual as ScrollViewer;
ScrollViewer searchChiled = null;
DependencyObject chiled;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
{
chiled = VisualTreeHelper.GetChild(visual, i);
if (chiled is Visual)
searchChiled = FindScroll(chiled as Visual);
if (searchChiled != null)
return searchChiled;
}
return null;
}
ScrollViewer scroller = FindScroll(YourReader as Visual);
if (scroller != null)
(scroller as ScrollViewer).ScrollToBottom();
Answer 4:
您可以使用下面的扩展方法来获得内滚动查看器:
public static class FlowDocumentScrollViewerExtensions
{
public static ScrollViewer GetScrollViewer(this FlowDocumentScrollViewer element) {
if (element == null) {
throw new ArgumentNullException(nameof(element));
}
return element.Template?.FindName("PART_ContentHost", element) as ScrollViewer;
}
}
此外,您可以使用这些扩展方法中添加内容之前检查滚动位置的ScrollViewer本身(如果你想滚动-only-如果滚动观众已经在最后为例):
public static class ScrollViewerExtensions
{
public static bool IsAtHome(this ScrollViewer element) {
if (element == null) {
throw new ArgumentNullException(nameof(element));
}
return element.VerticalOffset <= 0;
}
public static bool IsAtEnd(this ScrollViewer element) {
if (element == null) {
throw new ArgumentNullException(nameof(element));
}
return element.VerticalOffset >= element.ScrollableHeight;
}
}
后来才调用scrollViewer.ScrollToEnd()为例。