using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using PropertyMetadata = System.Windows.PropertyMetadata;
namespace YY.Admin.Core.Helper
{
///
/// ScrollViewer 辅助类:
/// 解决 ScrollViewer 包裹 TreeView / ListBox 等控件时,
/// 鼠标滚轮在内部控件上无法触发外层 ScrollViewer 滚动的问题。
///
public static class ScrollViewerHelper
{
///
/// 附加属性:是否启用鼠标滚轮事件向上传递
///
public static readonly DependencyProperty EnableMouseWheelPropagationProperty =
DependencyProperty.RegisterAttached(
"EnableMouseWheelPropagation", // 属性名
typeof(bool), // 属性类型
typeof(ScrollViewerHelper), // 所属类型
new PropertyMetadata(false, OnEnableMouseWheelPropagationChanged)); // 默认值+回调
///
/// 获取附加属性值(XAML 绑定/读取)
///
public static bool GetEnableMouseWheelPropagation(DependencyObject obj)
=> (bool)obj.GetValue(EnableMouseWheelPropagationProperty);
///
/// 设置附加属性值(XAML 设置)
///
public static void SetEnableMouseWheelPropagation(DependencyObject obj, bool value)
=> obj.SetValue(EnableMouseWheelPropagationProperty, value);
///
/// 当附加属性值发生变化时触发
///
private static void OnEnableMouseWheelPropagationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is UIElement element)
{
// 如果启用,则订阅 PreviewMouseWheel 事件
if ((bool)e.NewValue)
element.PreviewMouseWheel += Element_PreviewMouseWheel;
else
// 否则移除事件
element.PreviewMouseWheel -= Element_PreviewMouseWheel;
}
}
///
/// 当鼠标滚轮在目标控件上滚动时触发,
/// 将事件手动冒泡到上层(如 ScrollViewer)以实现滚动。
///
private static void Element_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
// 若事件已被处理,则直接返回
if (e.Handled) return;
// 标记事件已处理,防止重复触发
e.Handled = true;
// 构造一个新的 MouseWheelEventArgs,用于向父级转发
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent, // 指定为标准鼠标滚轮事件
Source = sender // 来源设为当前控件
};
// 获取父元素,并将事件重新抛出
if (sender is Control control)
{
var parent = control.Parent as UIElement;
parent?.RaiseEvent(eventArg);
}
}
}
}