当ViewingMode设置为滚动时,调整FlowDocumentReader的滚动增量?

我在FlowDocumentReader中使用ViewingMode =“Scroll”显示FlowDocument。 如果我在鼠标上使用滚轮,文档滚动速度非常慢。 我想增加滚动步骤。

  1. 我试图在控制面板中更改鼠标的滚动设置,但这没有任何效果。 我认为WPF忽略了FlowDocumentScrollViewer的设置。

  2. 我在FlowDocument和FlowDocumentReader上添加了一个Scroll事件,但是当我使用鼠标滚轮时,它不会触发。

  3. 我在FlowDocumentReader上添加了一个Loaded事件,得到了ScrollViewer后代,从滚动查看器的模板中找到了ScrollBar(“PART_VerticalScrollBar”)并调整了SmallChange和LargeChange属性。 这也没有任何影响。

有人有主意吗?

我们可以在Control的MouseWheel事件中修改它,比如Sohnee sugested,但是它只是针对一个特定情况解决了,你必须能够访问FlowDocumentReader,如果你使用类似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执行此操作的简短方法。 我们已经知道通过的项目将是某种forms的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属性。 此外,我们可以使用我们的辅助方法来获取元素中包含的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."); } } 

现在我们已经设置了Attached Property,我们可以创建一个简单的UI来演示它。 我将创建一个ListBox和一个FlowDocumentReaders,以便我们可以看到ScrollSpeed如何在多个控件中受到影响。

               

现在,在运行时,我们可以使用滑块来修改每列中的滚动速度,有趣的东西。

而不是使用滚动事件,捕获MouseWheel事件。

  

哇。 Rmoore的答案很精彩,但有点复杂。 我简化了一下。 对于那些不使用MVVM或者可以将代码放在有权访问目标元素的类中的人来说,这两种方法就足够了:

将此方法放入您的扩展程序:

  public static DependencyObject GetScrollViewer(this 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; } 

然后将第二个方法放到有权访问目标UI元素的类中,并将其订阅到“PreviewMouseWheel”事件

  private void HandleScrollSpeed(object sender, MouseWheelEventArgs e) { try { if (!(sender is DependencyObject)) return; ScrollViewer scrollViewer = (((DependencyObject)sender)).GetScrollViewer() as ScrollViewer; ListBox lbHost = sender as ListBox; //Or whatever your UI element is if (scrollViewer != null && lbHost != null) { double scrollSpeed = 1; //you may check here your own conditions if (lbHost.Name == "SourceListBox" || lbHost.Name == "TargetListBox") scrollSpeed = 2; 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."); } catch (Exception ex) { //Do something... } }