在wpf中禁用itemscontrol上的鼠标滚轮

ody*_*yth 26 .net c# wpf scrollwheel listbox

我有一个usercontrol,它有一个scrollviewer,然后是一堆子控件,如文本框,单选按钮和列表框等.我可以使用鼠标滚轮滚动父滚动查看器,直到我的鼠标落入列表框,然后,鼠标滚轮事件开始进入列表框.是否有任何方法让列表框将这些事件发送回父控件?从父控件的内侧删除列表框就像这个问题所示(当ScrollViewer的子控件超过时鼠标滚轮不工作)不是一个解决方案.

我试过了

void ListBox_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        e.Handled = true;
    }
Run Code Online (Sandbox Code Playgroud)

但那也没有用.

谢谢

Sim*_*Fox 35

您引用的答案正是造成问题的原因,ScrollViewer中的ListBox(由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>
Run Code Online (Sandbox Code Playgroud)

您可以选择在鼠标进入ScrollViewer时捕获鼠标,因此它会继续接收所有鼠标事件,直到释放鼠标为止,但是此选项需要您将任何进一步的鼠标事件传递给ScrollViewer中包含的控件(如果您想要一个响应...以下MouseEnter MouseLeave事件处理程序就足够了.

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

private void ScrollViewerMouseLeave(object sender, MouseEventArgs e)
{
    ((ScrollViewer)sender).ReleaseMouseCapture();
}
Run Code Online (Sandbox Code Playgroud)

我提供的解决方法都不是真的首选,我建议重新考虑你实际上要做的事情.如果你在你的问题中解释你想要实现的目标,我相信你会得到更多的建议......


Ama*_*duh 28

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

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

编辑:这是链接的解决方案:

"所以我提出了以下IgnoreMouseWheelBehavior.从技术上讲,它并没有忽略MouseWheel,而是将事件"转发"回来并从ListBox中退出.检查它."

/// <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);

  }

}
Run Code Online (Sandbox Code Playgroud)

以下是如何在XAML中使用它.

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

i命名空间来自Blend:

 xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Run Code Online (Sandbox Code Playgroud)


qua*_*ium 12

我遵循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);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 效果很好.为了更好的可移植性,可以用`UIElement`替换`DataGrid`类型.我也建议将它命名为"PassthroughMouseWheel",因为它就是它的作用.特别是它不会吃掉(最后忽略)车轮事件. - 哦,这是附属物,不是行为.这个类名在这里有误导性. (2认同)

Cam*_*and 9

正如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>
Run Code Online (Sandbox Code Playgroud)

NoWheelScrollViewer的实现非常简单.

public class NoWheelScrollViewer : ScrollViewer
{
    protected override void OnMouseWheel(MouseWheelEventArgs e)
    {
        // Do nothing
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,只要您希望列表框不处理鼠标滚轮.

<ListBox Template="{StaticResource NoWheelScrollListBoxTemplate}">
Run Code Online (Sandbox Code Playgroud)