2009-10-31 66 views

回答

7

通過創建文本範圍並監視變化,您可以檢測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的模板可以更改。如果這不會發生,這個代碼可以通過在FlowDocumentScrollViewer調用.ApplyTemplate(),然後計算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受保護。

+0

我不需要任何與FlowDocument和FlowDocumentScrollViewer可視化樹代碼。只需2次調用,1就可以創建並添加字符串中的段落,並將該段落添加到視圖中。 – 2015-02-25 18:33:43

2

掛鉤的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(); 
+0

我只使用FlowDocument和FlowDocumentscrollViewer。上面的BringIntoView解決方案完全適合我。我不需要VisualTreeHelper 我的解決方案是使用Dispatcher.Invoke編寫創建段落,將該段落存儲爲變量,然後再次將Dispatcher.Invoke放入視圖中。 這似乎是最簡單的方法。 – 2015-02-25 18:32:38

0

您可以使用下面的擴展方法來獲得內滾動查看器:

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()爲例。