将ListView中的滚动事件冒泡到其父级

M. *_*ley 54 wpf listview scroll event-bubbling

在我的WPF应用程序我有一个ListViewScrollViewer.VerticalScrollBarVisibility设置为Disabled.它包含在一个ScrollViewer.当我尝试使用鼠标滚轮时ListView,外部ScrollViewer不会滚动,因为它ListView正在捕获滚动事件.

如何强制ListView允许滚动事件冒泡到ScrollViewer

key*_*yle 82

您需要在内部列表视图中捕获预览鼠标滚轮事件

ctl.PreviewMouseWheel += PreviewMouseWheel;
Run Code Online (Sandbox Code Playgroud)

然后停止滚动listview并在父列表视图中引发事件.

private static void PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    if (!e.Handled)
    {
        e.Handled = true;
        var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
        eventArg.RoutedEvent = UIElement.MouseWheelEvent;
        eventArg.Source = sender;
        var parent = ((Control)sender).Parent as UIElement;
        parent.RaiseEvent(eventArg);
    }
}
Run Code Online (Sandbox Code Playgroud)

几个月前,@ robert-wagner为我解决了这个问题.

  • 我不能相信:http://stackoverflow.com/questions/3498686/wpf-remove-scrollviewer-from-treeview (7认同)

mak*_*akc 37

使用附加行为的另一个好方案.我喜欢它,因为它破坏了Control的解决方案.

创建一个无滚动行为,它将捕获PreviewMouseWheel(Tunneling)事件并引发一个新的MouseWheelEvent(冒泡)

public sealed class IgnoreMouseWheelBehavior : Behavior<UIElement>
{

  protected override void OnAttached( )
  {
    base.OnAttached( );
    AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel ;
  }

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

void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{

    e.Handled = true;

    var e2 = new MouseWheelEventArgs(e.MouseDevice,e.Timestamp,e.Delta);
    e2.RoutedEvent = UIElement.MouseWheelEvent;
        AssociatedObject.RaiseEvent(e2);

    }
}
Run Code Online (Sandbox Code Playgroud)

然后将行为附加到具有嵌套ScrollViewers案例的任何UIElement

 <ListBox Name="ForwardScrolling">
    <i:Interaction.Behaviors>
        <local:IgnoreMouseWheelBehavior />
    </i:Interaction.Behaviors>
</ListBox>
Run Code Online (Sandbox Code Playgroud)

所有归功于约什爱因斯坦博客

  • 对于使用此解决方案的任何人,您必须确保添加了`using System.Windows.Interactivity`命名空间,该命名空间可以使用NuGet包中的命令`Install-Package Expression.Blend.Sdk`添加到当前项目中经理控制台.此外,您必须使用`xmlns:i ="http://schemas.microsoft.com/expression/2010/interactivity"将.命名空间添加到.xaml文件中. (7认同)

DLe*_*Leh 8

如果你来这里寻找一个解决方案,只有当孩子在顶部并向上滚动或向下滚动并向下滚动时才能使事件冒泡,这是一个解决方案.我只使用DataGrid对此进行了测试,但它也应该与其他控件一起使用.

public class ScrollParentWhenAtMax : Behavior<FrameworkElement>
{
    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 = GetVisualChild<ScrollViewer>(this.AssociatedObject);
        var scrollPos = scrollViewer.ContentVerticalOffset;
        if ((scrollPos == scrollViewer.ScrollableHeight && e.Delta < 0)
            || (scrollPos == 0 && e.Delta > 0))
        {
            e.Handled = true;
            var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
            e2.RoutedEvent = UIElement.MouseWheelEvent;
            AssociatedObject.RaiseEvent(e2);
        }
    }

    private static T GetVisualChild<T>(DependencyObject parent) where T : Visual
    {
        T child = default(T);

        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
            {
                child = GetVisualChild<T>(v);
            }
            if (child != null)
            {
                break;
            }
        }
        return child;
    }
}
Run Code Online (Sandbox Code Playgroud)

要附加此行为,请将以下XMLNS和XAML添加到您的元素:

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

    <i:Interaction.Behaviors>
        <shared:ScrollParentWhenAtMax />
    </i:Interaction.Behaviors>
Run Code Online (Sandbox Code Playgroud)


小智 5

根据您的具体情况,有不同的方法,但我发现这种方法效果很好。假设你的基本情况是这样的:

<Window Height="200" Width="200">
<Grid>
    <ScrollViewer Name="sViewer">
        <StackPanel>
            <Label Content="Scroll works here" Margin="10" />
            <ListView Name="listTest" Margin="10" 
                      PreviewMouseWheel="listTest_PreviewMouseWheel" 
                      ScrollViewer.VerticalScrollBarVisibility="Disabled">
                <ListView.ItemsSource>
                    <Int32Collection>
                        1,2,3,4,5,6,7,8,9,10
                    </Int32Collection>
                </ListView.ItemsSource>
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Column 1" />
                    </GridView>
                </ListView.View>
            </ListView>
        </StackPanel>
    </ScrollViewer>
</Grid>
</Window>
Run Code Online (Sandbox Code Playgroud)

在 PreviewMouseWheel 期间自行引发 MouseWheelEvent 似乎会强制 ScrollViewer 工作。我希望我知道为什么,这似乎非常违反直觉。

private void listTest_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
    e.Handled = true;
    MouseWheelEventArgs e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
    e2.RoutedEvent = UIElement.MouseWheelEvent;
    listTest.RaiseEvent(e2);
}
Run Code Online (Sandbox Code Playgroud)