using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace WxOrder.Framework.Commons { /// /// 让页面级 ScrollViewer 在鼠标悬停在子控件(如 DataGrid、图表等)上时也能随鼠标滚轮滚动。 /// 用法:在 ScrollViewer 上设置 common:ScrollViewerBehavior.FixMouseWheel="True"。 /// public static class ScrollViewerBehavior { public static readonly DependencyProperty FixMouseWheelProperty = DependencyProperty.RegisterAttached( "FixMouseWheel", typeof(bool), typeof(ScrollViewerBehavior), new PropertyMetadata(false, OnFixMouseWheelChanged)); public static bool GetFixMouseWheel(DependencyObject obj) => (bool)obj.GetValue(FixMouseWheelProperty); public static void SetFixMouseWheel(DependencyObject obj, bool value) => obj.SetValue(FixMouseWheelProperty, value); private static void OnFixMouseWheelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (!(d is ScrollViewer scrollViewer)) { return; } if ((bool)e.NewValue) { scrollViewer.PreviewMouseWheel += OnPreviewMouseWheel; } else { scrollViewer.PreviewMouseWheel -= OnPreviewMouseWheel; } } private static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (e.Handled || !(sender is ScrollViewer scrollViewer) || scrollViewer.ScrollableHeight <= 0) { return; } if (!(e.OriginalSource is DependencyObject original)) { return; } // 从鼠标所在控件向上查找,确认它属于当前 ScrollViewer var current = original; var inside = false; while (current != null) { if (ReferenceEquals(current, scrollViewer)) { inside = true; break; } // 若鼠标位于一个能自行纵向滚动的内部 ScrollViewer 上(例如下拉列表、 // 启用了滚动的表格),则交给内部处理,避免抢走它的滚动。 if (current is ScrollViewer inner && inner.ComputedVerticalScrollBarVisibility == Visibility.Visible && inner.ScrollableHeight > 0) { return; } current = VisualTreeHelper.GetParent(current); } if (!inside) { return; } // 按系统默认的滚轮行数滚动当前页面 var lines = (int)(e.Delta / Mouse.MouseWheelDeltaForOneLine * SystemParameters.WheelScrollLines); if (lines == 0) { lines = e.Delta > 0 ? 1 : -1; } if (lines < 0) { for (var i = 0; i < -lines; i++) { scrollViewer.LineDown(); } } else { for (var i = 0; i < lines; i++) { scrollViewer.LineUp(); } } e.Handled = true; } } }