截取鼠标滚轮事件的简单行为

实现行为

当内部事件处于其上限或下限时,此行为将导致内部 ScrollViewer 的鼠标滚轮事件冒泡到父 ScrollViewer。如果没有这种行为,事件将永远不会超出内部的时间。

public class BubbleMouseWheelEvents : Behavior<UIElement>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.PreviewMouseWheel += PreviewMouseWheel;
    }

    protected override void OnDetaching()
    {
        this.AssociatedObject.PreviewMouseWheel -= PreviewMouseWheel;
        base.OnDetaching();
    }

    private void PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        var scrollViewer = AssociatedObject.GetChildOf<ScrollViewer>(includeSelf: true);
        var scrollPos = scrollViewer.ContentVerticalOffset;
        if ((scrollPos == scrollViewer.ScrollableHeight && e.Delta < 0) || (scrollPos == 0 && e.Delta > 0))
        {
            UIElement rerouteTo = AssociatedObject;
            if (ReferenceEquals(scrollViewer, AssociatedObject))
            {
                rerouteTo = (UIElement) VisualTreeHelper.GetParent(AssociatedObject);
            }

            e.Handled = true;
            var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
            e2.RoutedEvent = UIElement.MouseWheelEvent;
            rerouteTo.RaiseEvent(e2);
        }
    }
}

行为是 Behavior<T> 基类的子类,T 是它能够附加的控件类型,在本例中为 UIElement。当从 XAML 实例化 Behavior 时,调用 OnAttached 方法。此方法允许行为挂钩来自它所附加的控件的事件(通过 AssociatedControl)。类似的方法,当需要从关联元素取消挂钩行为时,调用 OnDetached。应注意删除任何事件处理程序,或以其他方式清理对象以避免内存泄漏。

此行为会挂钩到 PreviewMouseWheel 事件,该事件会在 ScrollViewer 有机会查看之前对其进行更改以拦截事件。它检查位置以查看是否需要将事件沿可视树转发到任何更高层次的层次。如果是这样,它将 e.Handled 设置为 true 以防止事件的默认操作。然后它提出了一个新的 MouseWheelEvent 路由到 AssociatedObject。否则,事件将正常路由。

将行为附加到 XAML 中的元素

首先,必须先将 interactivity xml-namespace 引入范围,然后才能在 XAML 中使用它。将以下行添加到 XAML 的命名空间。

xmlns:interactivity =“ http://schemas.microsoft.com/expression/2010/interactivity

可以像这样附加行为:

<ScrollViewer>
    <!--...Content...-->
    <ScrollViewer>
        <interactivity:Interaction.Behaviors>
            <behaviors:BubbleMouseWheelEvents />
        </interactivity:Interaction.Behaviors>
        <!--...Content...-->
    </ScrollViewer>
    <!--...Content...-->.
</ScrollViewer>

这将创建一个 Behaviors 集合作为内部 ScrollViewer 上的附加属性,其中包含 BubbleMouseWheelEvents 行为。

此特定行为也可以附加到包含嵌入式 ScrollViewer 的任何现有控件,例如 GridView,并且它仍然可以正常运行。