2009-05-18 3 views
6

Я показываю FlowDocument в FlowDocumentReader с ViewMode = "Scroll". Если я использую колесо на моей мыши, документ прокручивается очень медленно. Я хотел бы увеличить шаг прокрутки.Настроить увеличение прокрутки FlowDocumentReader при выборе режима просмотра для прокрутки?

  1. Я попытался изменить настройку прокрутки мыши на панели управления, но это не имеет никакого эффекта. Я думаю, что WPF игнорирует этот параметр для FlowDocumentScrollViewer.

  2. Я добавил событие Scroll в FlowDocument и FlowDocumentReader, но это не срабатывает при использовании колеса мыши.

  3. Я добавил Loaded событие на FlowDocumentReader, получил потомок ScrollViewer, нашел ScrollBar («PART_VerticalScrollBar») из шаблона зрительского скроллинга и регулировать свойства LargeChange SmallChange &. Это также не имело никакого эффекта.

У кого-нибудь есть идеи?

+0

Если твинг, который вы должны были выполнить в ответ, был с «/ 6» для стандартной скорости, я понял лучший способ сделать это, отвечая на другой вопрос. Если вы вместо этого умножаете SystemInformation.MouseWheelScrollLines/3 (текущие настройки компьютера/по умолчанию), то он должен работать на основе пользовательских настроек мыши вместо статической скорости. – rmoore

ответ

19

Мы можем изменить это в случае MouseWheel элемента управления, как Sohnee мотивационные, но тогда это было бы просто решить для одного конкретного случая, и вы должны иметь доступ к 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, мы можем, наконец, изменить скорость прокрутки. Нам нужно получить свойство ScrollSpeed ​​из объекта DependancyObject, который отправляется через. Кроме того, мы можем использовать наш вспомогательный метод, чтобы получить ScrollViewer, который содержится внутри элемента. Как только у нас есть эти две вещи, мы можем получить и изменить VerticalOffset ScrollViewer. Я обнаружил, что разделение MouseWheelEventArgs.Delta, которое является величиной, которую изменило колесо мыши, на 6 получает приблизительно скорость прокрутки по умолчанию. Итак, если мы умножим это на наш модификатор ScrollSpeed, мы можем получить новое значение смещения. Затем мы можем установить VerticalOffset ScrollViewer с помощью метода ScrollToVerticalOffset, который он предоставляет.

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."); 
    } 
} 

Теперь, когда у нас установлено наше прикрепленное свойство, мы можем создать простой пользовательский интерфейс, чтобы продемонстрировать его. Я собираюсь создать 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

+1

Он работает блестяще! Мне только пришлось немного подправить его, чтобы скомпилировать его и работать. – Christo

0

Вместо использования события прокрутки захватите событие MouseWheel.

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

Я попробую это, может быть, я смогу заставить работать. Я в значительной степени смирился с мыслью, что этого будет очень сложно достичь, не имея необходимости писать много кода. – Christo

Смежные вопросы