如何在WPF中的ListBox中捕获鼠标单击项?

38

我想在鼠标单击ListBox中的项目时收到通知,无论它是否已被选中。

我搜索并找到了这个:(http://kevin-berridge.blogspot.com/2008/06/wpf-listboxitem-double-click.html看一下评论)

private void AddDoubleClickEventStyle(ListBox listBox, MouseButtonEventHandler mouseButtonEventHandler)
{
    if (listBox.ItemContainerStyle == null)
        listBox.ItemContainerStyle = new Style(typeof(ListBoxItem));
    listBox.ItemContainerStyle.Setters.Add(new EventSetter()
    {
        Event = MouseDoubleClickEvent,
        Handler = mouseButtonEventHandler
    });
}

//Usage:
AddDoubleClickEventStyle(listView1, new MouseButtonEventHandler(listView1_MouseDoubleClick));
这段代码可以用于双击事件,但是我无法将其应用到单击事件上。我尝试使用MouseLeftButtonDownEvent,因为没有MouseClick事件,但它没有被调用。
另一个一般性的问题是: 如何查看已存在的事件以及哪些处理程序与它们对应,以及何时它们实际上会起作用?例如,怎样才能知道需要MouseButtonEventHandler处理程序来处理MouseDoubleClickEvent事件?也许对于MouseLeftButtonDownEvent事件而言,我需要其他的处理程序,这就是它不起作用的原因?
我还尝试了继承ListBoxItem并重写OnMouseLeftButtonDown方法,但它也没有被调用。
Marc

我选择用按钮来包装每个列表项,并使用按钮事件。https://dev59.com/snPYa4cB1Zd3GeqPgDXL - user1021364
6个回答

58
我认为你的MouseLeftButtonDown处理程序未被调用,是因为ListBox在内部使用此事件来触发其SelectionChanged事件(认为在绝大多数情况下,SelectionChanged就足够了)。 也就是说,你有两种选择。
首先,你可以订阅PreviewLeftButtonDown事件。大多数路由事件具有冒泡的路由策略,这意味着生成事件的控件首先获取它,如果没有处理,则事件沿着可视树向上工作,使每个控件都有机会处理事件。另一方面,Preview事件是隧道式的。这意味着它们从可视树的根(通常为Window)开始,然后向下工作到生成事件的控件。由于你的代码将有机会在ListBoxItem之前处理事件,因此将触发此事件(不会被处理),从而调用你的事件处理程序。你可以通过将样本中的MouseDoubleClickEvent替换为PreviewMouseLeftButtonDown来实现此选项。
另一种选择是注册一个类处理程序,每当ListBoxItem触发MouseLeftButtonDown事件时,该处理程序都会收到通知。像这样完成:
```csharp EventManager.RegisterClassHandler(typeof(ListBoxItem), ListBoxItem.MouseLeftButtonDownEvent, new RoutedEventHandler(YourHandler)); ```
EventManager.RegisterClassHandler(typeof(ListBoxItem),
    ListBoxItem.MouseLeftButtonDownEvent,
    new RoutedEventHandler(this.MouseLeftButtonDownClassHandler));

private void OnMouseLeftButtonDown(object sender, RoutedEventArgs e)
{
}

Class Handlers被称为优先于任何其他事件处理程序的事件处理程序,但它们会为应用程序中指定类型的所有控件调用。因此,如果您有两个 ListBoxes,则无论在哪个列表框中单击任何一个 ListBoxItem,都将调用此事件处理程序。

至于您的第二个问题,了解您需要针对给定事件使用哪种类型的事件处理程序以及查看给定控件可用的事件列表的最佳方法是使用MSDN文档。例如,所有由 ListBoxItem 处理的事件列表位于http://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx。如果单击事件链接,它会包括该事件的事件处理程序类型。


2
有一件事,我想补充一下。不要使用ButtonDown事件,而是使用ButtonUp事件。当你按住按钮时立即执行操作的应用程序只会让人感到奇怪。这也有一个用户交互的原因。在基本上所有流行的应用程序中,您可以通过在释放按钮之前移动鼠标来取消按钮点击。 - Stefan Fabian
@StefanFabian 是的,但是列表框中的项目通常在鼠标按下时被选中。而移动鼠标仍然可以工作。 - Wouter
@StefanFabian 我已经尝试了预览事件(向上和向下),我喜欢你的想法,即通过向上移动鼠标可以将其移出控件并取消单击,但我没有看到这种情况发生。无论我在释放按钮时鼠标在哪里,我的事件都会被调用(使用System.Windows.Interaction触发器方法)。 - Paul Gibson
@PaulGibson 嗯,我认为他们做出了这样的设计决策:如果没有取消,就称之为“always”,只有在不取消时才会被点击。因此,如果您想要取消功能,就必须自己检查鼠标是否仍停留在元素上。 - Stefan Fabian

25

还有另一种方法-处理PreviewMouseDown事件并检查它是否由列表项触发:

在XAML中:

<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/> 
在代码后台:
private void PlaceholdersListBox_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    var item = ItemsControl.ContainerFromElement(sender as ListBox, e.OriginalSource as DependencyObject) as ListBoxItem;
    if (item != null)
    {
        // ListBox item clicked - do some cool things here
    }
}

受到这个答案的启发,但它使用了列表框名称,我建议使用发送方参数以避免不必要的依赖关系。


有没有办法找到单击的 ListBoxItem 的索引? - ymbcKxSw
到目前为止,我找到的最好解决方案是遍历项目列表,直到找到匹配项。这对我的情况有效,因为我的列表非常小,但对于其他人可能不会很好扩展。 - ymbcKxSw
花了很多时间寻找正确的事件,但没有成功...非常感谢Pavel! - BlueDev

22

我认为Andy的回答中的第一种选项,使用PreviewMouseLeftButtonDown是解决这个问题的正确方法。在XAML中,它应该如下所示:

<ListBox Name="testListBox">
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <EventSetter
                Event="PreviewMouseLeftButtonDown" 
                Handler="ListBox_MouseLeftButtonDown" />
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

10

在ListBox中获取MouseDown事件的另一种方法,是使用AddHandler方法的handledEventsToo签名来为那些被标记为已处理事件添加事件处理程序:

myListBox.AddHandler(UIElement.MouseDownEvent, 
        new MouseButtonEventHandler(ListBox_MouseDown), true);

上面的第三个参数是handledEventsToo,它确保无论是否已标记为HandledListBox中的ListBoxItem会这样做),此处理程序都将被调用。
有关说明,请参见将路由事件标记为已处理和类处理
例如,请参见如何在ListBox上附加到MouseDown事件


4
你可以使用 Event="MouseLeftButtonUp"
"PreviewLeftButtonDown" 不同,它也会处理 ListBoxItem。

0

您可以使用SelectionChanged事件的SelectionChangedEventArgs参数来查找通过AddedItems和RemovedItems添加或删除的项目,通常只有最新点击的项目,如果不是,则查看最后一个项目,即计数-1。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接