在wpf中禁用项目控制上的鼠标滚轮

我有一个用户控件,它有一个滚动查看器,然后一堆儿童控制,如文本框,单选button,列表框等内部。 我可以使用鼠标滚轮滚动父滚动查看器,直到我的鼠标落在一个列表框内,然后鼠标滚轮事件开始进入列表框。 有没有办法让列表框发送这些事件回到父控制? 从这个问题的父控件内部移除列表框( 当滚动查看器的子控件时鼠标滚轮不工作 )不是一个解决scheme。

我努力了

void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { e.Handled = true; } 

但那也没用。

谢谢

你所引用的答案正是导致你的问题,你的ScrollViewer中的列表框(它是由ScrollViewer组成)捕获MouseWheel事件并处理它,防止它冒泡,因此ScrollViewer不知道事件曾经发生过。

使用以下极其简单的ControlTemplate来显示ListBox(注意它没有ScrollViewer,因此MouseWheel事件将不会被捕捉到)。ScrollViewer仍然会用鼠标滚动到ListBox上。

 <UserControl.Resources> <ControlTemplate x:Key="NoScroll"> <ItemsPresenter></ItemsPresenter> </ControlTemplate> </UserControl.Resources> <ScrollViewer> <SomeContainerControl> <.... what ever other controls are inside your ScrollViewer> <ListBox Template="{StaticResource NoScroll}"></ListBox> <SomeContainerControl> </ScrollViewer> 

当鼠标进入ScrollViewer的时候,你可以select捕捉鼠标,直到鼠标被释放,鼠标事件才会继续,但是这个选项会要求你将任何进一步的鼠标事件分割到ScrollViewer中的控件上。想要一个响应…下面的MouseEnter MouseLeave事件处理程序就足够了。

 private void ScrollViewerMouseEnter(object sender, MouseEventArgs e) { ((ScrollViewer)sender).CaptureMouse(); } private void ScrollViewerMouseLeave(object sender, MouseEventArgs e) { ((ScrollViewer)sender).ReleaseMouseCapture(); } 

我所提供的两种解决方法都不是最好的,但我build议重新考虑你实际上正在做的事情。 如果你解释你正在努力实现你的问题,我相信你会得到更多的build议…

这可以通过附加的行为来完成。

http://josheinstein.com/blog/index.php/2010/08/wpf-nested-scrollviewer-listbox-scrolling/

编辑:这是链接的解决scheme:

“所以我想出了下面的IgnoreMouseWheelBehavior,从技术上说,它并不是忽略MouseWheel,而是将事件”转发“回来并从列表框中移出来,检查它。

 /// <summary> /// Captures and eats MouseWheel events so that a nested ListBox does not /// prevent an outer scrollable control from scrolling. /// </summary> 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); } } 

这里是你如何在XAML中使用它。

 <ScrollViewer Name="IScroll"> <ListBox Name="IDont"> <i:Interaction.Behaviors> <local:IgnoreMouseWheelBehavior /> </i:Interaction.Behaviors> </ListBox> </ScrollViewer> 

我的命名空间来自Blend:

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

我遵循Amanduh的方法来解决与滚动查看器中的多个数据网格相同的问题,但在WPF中:

 public sealed class IgnoreMouseWheelBehavior { public static bool GetIgnoreMouseWheel(DataGrid gridItem) { return (bool)gridItem.GetValue(IgnoreMouseWheelProperty); } public static void SetIgnoreMouseWheel(DataGrid gridItem, bool value) { gridItem.SetValue(IgnoreMouseWheelProperty, value); } public static readonly DependencyProperty IgnoreMouseWheelProperty = DependencyProperty.RegisterAttached("IgnoreMouseWheel", typeof(bool), typeof(IgnoreMouseWheelBehavior), new UIPropertyMetadata(false, OnIgnoreMouseWheelChanged)); static void OnIgnoreMouseWheelChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e) { var item = depObj as DataGrid; if (item == null) return; if (e.NewValue is bool == false) return; if ((bool)e.NewValue) item.PreviewMouseWheel += OnPreviewMouseWheel; else item.PreviewMouseWheel -= OnPreviewMouseWheel; } static void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e) { e.Handled = true; var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) {RoutedEvent = UIElement.MouseWheelEvent}; var gv = sender as DataGrid; if (gv != null) gv.RaiseEvent(e2); } } 

正如Simon所说的那样,它是捕获事件的标准ListBox模板中的ScrollViewer。 要绕过它,你可以提供你自己的模板。

 <ControlTemplate x:Key="NoWheelScrollListBoxTemplate" TargetType="ListBox"> <Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="1,1,1,1" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True"> <!-- This is the new control --> <l:NoWheelScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" /> </l:NoWheelScrollViewer> </Border> <ControlTemplate.Triggers> <Trigger Property="UIElement.IsEnabled" Value="False"> <Setter TargetName="Bd" Property="Panel.Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" /> </Trigger> <Trigger Property="ItemsControl.IsGrouping" Value="True"> <Setter Property="ScrollViewer.CanContentScroll" Value="False" /> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> 

NoWheelScrollViewer的实现非常简单。

 public class NoWheelScrollViewer : ScrollViewer { protected override void OnMouseWheel(MouseWheelEventArgs e) { // Do nothing } } 

然后,每当你想要一个列表框不处理鼠标滚轮。

 <ListBox Template="{StaticResource NoWheelScrollListBoxTemplate}"> 

一个简单的解决scheme对我来说是重写内部控制模板,以删除滚动查看器(视需要)如此

例如,我有这样的结构

  • ListView(a)

    • ListView(b)

      • ListView(c)

我想把(b)的鼠标滚轮滚动到(a),但想保持(c)的鼠标滚轮可用。 我简单地重写(b)的模板。 这允许我将(b)的内容(c)除外(a)。 另外,我仍然可以滚动(c)的内容。 如果我想删除即使(三),那么我不得不重复相同的一步。

 <ListView.Template> <ControlTemplate> <ItemsPresenter /> </ControlTemplate> </ListView.Template> 

我正在尝试将Simon Fox的答案改写为DataGrid。 我发现模板隐藏了我的头文件,而我从来没有通过在C#中完成mouseLeave事件。 这最终是对我有用的:

  private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { ((DataGrid)sender).CaptureMouse(); } private void DataGrid_MouseWheel(object sender, MouseWheelEventArgs e) { ((DataGrid)sender).ReleaseMouseCapture(); } 

一个修改后的西蒙·福克斯的解决scheme,如果原来不工作:

 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(); } static void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e) { if (!(sender is DependencyObject)) { return; } DependencyObject parent = VisualTreeHelper.GetParent((DependencyObject) sender); if (!(parent is UIElement)) { return; } ((UIElement) parent).RaiseEvent( new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) { RoutedEvent = UIElement.MouseWheelEvent }); e.Handled = true; } } 

您必须从ScrollViewer(它工作),而不是从列表框中听PreviewMouseWheel。