2009-05-18 118 views
6

我使用ViewingMode =「Scroll」在FlowDocumentReader中顯示FlowDocument。如果我在鼠標上使用滾輪,文檔滾動速度非常緩慢。我想增加滾動步驟。當ViewingMode設置爲滾動時調整FlowDocumentReader的滾動增量?

  1. 我試圖在控制面板中更改鼠標的滾動設置,但沒有任何效果。我認爲WPF忽略了FlowDocumentScrollViewer的設置。

  2. 我在FlowDocument和FlowDocumentReader上添加了一個Scroll事件,但在使用鼠標滾輪時不會觸發。

  3. 我已經添加在FlowDocumentReader一個Loaded事件,得到的ScrollViewer後裔, 從滾動觀衆的模板中找到的滾動條(「PART_VerticalScrollBar」),並調整了SmallChange & LargeChange屬性。這也沒有任何影響。

任何人有什麼想法?

+0

如果你對我的回答所要做的tweeking與標準速度的'/ 6'一樣,我在回答另一個問題時意識到了一個更好的方法。如果您乘以SystemInformation.MouseWheelScrollLines/3(當前計算機設置/默認值),則它應該基於用戶鼠標設置而不是靜態速度工作。 – rmoore 2009-06-10 23:29:07

回答

19

我們可以在控制的鼠標滾輪事件修改此,像Sohnee sugested,但隨後它會只是需要解決的一個特定的情況下,你得有訪問FlowDocumentReader,而如果你的usinging像MVVM,你不會。相反,我們可以創建一個附屬屬性,然後我們可以使用ScrollViewer在任何元素上設置屬性。在定義我們的附加屬性時,我們還需要一個PropertyChanged回調函數,我們將在其中執行滾動速度的實際修改。我還給了我的財產默認值爲1,我將要使用的速度範圍是.1x到3x,儘管你可以輕鬆做到1-10。

public static double GetScrollSpeed(DependencyObject obj) 
{ 
    return (double)obj.GetValue(ScrollSpeedProperty); 
} 

public static void SetScrollSpeed(DependencyObject obj, double value) 
{ 
    obj.SetValue(ScrollSpeedProperty, value); 
} 

public static readonly DependencyProperty ScrollSpeedProperty = 
    DependencyProperty.RegisterAttached(
    "ScrollSpeed", 
    typeof(double), 
    typeof(ScrollHelper), 
    new FrameworkPropertyMetadata(
     1.0, 
     FrameworkPropertyMetadataOptions.Inherits & FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
     new PropertyChangedCallback(OnScrollSpeedChanged))); 

private static void OnScrollSpeedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
{ 
} 

現在,我們有我們的附加屬性,我們需要處理滾動,要做到這一點,在我們OnScrollSpeedChanged可以處理PreviewMouseWheel事件。我們希望鉤入PreviewMouseWheel,因爲它是在ScrollViewer可以處理標準MouseWheel事件之前發生的隧道事件。

目前,PreviewMouseWheel處理程序正在接受FlowDocumentReader或其他我們將它綁定的東西,但我們需要的是ScrollViewer。由於可能有很多事情:ListBox,FlowDocumentReader,WPF Toolkit Grid,ScrollViewer等,我們可以使用VisualTreeHelper來做一個簡短的方法。我們已經知道,通過的項目將是某種形式的DependancyObject,所以我們可以使用一些遞歸來查找ScrollViewer是否存在。

public static DependencyObject GetScrollViewer(DependencyObject o) 
{ 
    // Return the DependencyObject if it is a ScrollViewer 
    if (o is ScrollViewer) 
    { return o; } 

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++) 
    { 
     var child = VisualTreeHelper.GetChild(o, i); 

     var result = GetScrollViewer(child); 
     if (result == null) 
     { 
      continue; 
     } 
     else 
     { 
      return result; 
     } 
    } 

    return null; 
} 

private static void OnScrollSpeedChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) 
{ 
    var host = o as UIElement; 
    host.PreviewMouseWheel += new MouseWheelEventHandler(OnPreviewMouseWheelScrolled); 
} 

現在我們可以得到ScrollViwer,我們可以最終修改滾動速度。我們需要從正在發送的DependancyObject中獲取ScrollSpeed屬性。另外,我們可以使用我們的helper方法來獲取元素中包含的ScrollViewer。一旦我們有了這兩件事,我們就可以獲得並修改ScrollViewer的VerticalOffset。我發現將MouseWheelEventArgs.Delta(鼠標滾輪改變的量)除以6得到大約默認的滾動速度。所以,如果我們用ScrollSpeed修飾符乘以那個,我們就可以得到新的偏移值。然後,我們可以使用它公開的ScrollToVerticalOffset方法來設置ScrollViewer的VerticalOffset。

private static void OnPreviewMouseWheelScrolled(object sender, MouseWheelEventArgs e) 
{ 
    DependencyObject scrollHost = sender as DependencyObject; 

    double scrollSpeed = (double)(scrollHost).GetValue(Demo.ScrollSpeedProperty); 

    ScrollViewer scrollViewer = GetScrollViewer(scrollHost) as ScrollViewer; 

    if (scrollViewer != null) 
    { 
     double offset = scrollViewer.VerticalOffset - (e.Delta * scrollSpeed/6); 
     if (offset < 0) 
     { 
      scrollViewer.ScrollToVerticalOffset(0); 
     } 
     else if (offset > scrollViewer.ExtentHeight) 
     { 
      scrollViewer.ScrollToVerticalOffset(scrollViewer.ExtentHeight); 
     } 
     else 
     { 
      scrollViewer.ScrollToVerticalOffset(offset); 
     } 

     e.Handled = true; 
    } 
    else 
    { 
     throw new NotSupportedException("ScrollSpeed Attached Property is not attached to an element containing a ScrollViewer."); 
    } 
} 

現在我們已經設置了附加屬性,我們可以創建一個簡單的UI來演示它。我將創建一個ListBox和一個FlowDocumentReaders,以便我們可以看到ScrollSpeed如何在多個控件中受到影響。

<UniformGrid Columns="2"> 
    <DockPanel> 
     <Slider DockPanel.Dock="Top" 
      Minimum=".1" 
      Maximum="3" 
      SmallChange=".1" 
      Value="{Binding ElementName=uiListBox, Path=(ScrollHelper:Demo.ScrollSpeed)}" /> 
     <ListBox x:Name="uiListBox"> 
      <!-- Items --> 
     </ListBox> 
    </DockPanel> 
    <DockPanel> 
     <Slider DockPanel.Dock="Top" 
      Minimum=".1" 
      Maximum="3" 
      SmallChange=".1" 
      Value="{Binding ElementName=uiListBox, Path=(ScrollHelper:Demo.ScrollSpeed)}" /> 
     <FlowDocumentReader x:Name="uiReader" 
      ViewingMode="Scroll"> 
      <!-- Flow Document Content --> 
     </FlowDocumentReader> 
    </DockPanel> 
</UniformGrid> 

現在,運行時,我們可以使用滑塊來修改每列中的滾動速度,有趣的東西。

+1

太棒了! 我正在使用類似於MVVM的東西,您的方法將完美工作。我期待着實施它。 Thanx! – Christo 2009-06-10 15:52:18

0

而不是使用滾動事件捕獲MouseWheel事件。

<FlowDocumentReader MouseWheel="..."> 
+0

我會試試這個,也許我可以找點工作。我幾乎完全拒絕這樣的想法,即在不必編寫大量代碼的情況下實現這將非常困難。 – Christo 2009-06-09 19:28:14