【问题标题】:How to capture a mouse click on an Item in a ListBox in WPF?如何在 WPF 中的 ListBox 中捕获鼠标单击项目?
【发布时间】:2010-11-19 06:33:40
【问题描述】:

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

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

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

这可行,但它适用于DoubleClick。但是,我无法使其单击一下。我试过MouseLeftButtonDownEvent - 因为似乎没有MouseClick 事件,但它没有被调用。

一个更笼统的问题:我如何才能看到确实存在哪些事件,哪些处理程序对应于它们以及它们何时实际执行某些操作?例如,什么告诉我对于MouseDoubleClickEvent 我需要MouseButtonEventHandler?也许对于MouseLeftButtonDownEvent,我需要其他一些处理程序,这就是它不起作用的原因?

我也尝试继承 ListBoxItem 并覆盖 OnMouseLeftButtonDown - 但它也没有被调用。

马克

【问题讨论】:

标签: wpf listbox events click listboxitem


【解决方案1】:

我认为Andy 的答案中的第一个选项,即使用PreviewMouseLeftButtonDown,是解决此问题的方法。在 XAML 中,它看起来像这样:

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

【讨论】:

    【解决方案2】:

    我相信你的MouseLeftButtonDown 处理程序没有被调用,因为ListBox 在内部使用这个事件来触发它的SelectionChanged 事件(认为在绝大多数情况下,SelectionChanged 就是你所需要的)。也就是说,您有几个选择。

    首先,您可以改为订阅PreviewLeftButtonDown 事件。大多数路由事件都有 Bubbling 的路由策略,这意味着生成事件的控件首先获取它,如果不处理,事件会沿着可视化树向上移动,从而使每个控件都有机会处理事件。另一方面,预览事件是隧道。这意味着它们从可视化树的根部开始(通常是Window),然后一直向下到生成事件的控件。由于您的代码将有机会在ListBoxItem 之前处理事件,因此这将被触发(而不是被处理),因此您的事件处理程序将被调用。您可以通过将示例中的 MouseDoubleClickEvent 替换为 PreviewMouseLeftButtonDown 来实现此选项。

    另一个选项是注册一个类处理程序,只要ListBoxItem 触发MouseLeftButtonDown 事件,就会通知该处理程序。这样做是这样的:

    EventManager.RegisterClassHandler(typeof(ListBoxItem),
        ListBoxItem.MouseLeftButtonDownEvent,
        new RoutedEventHandler(this.MouseLeftButtonDownClassHandler));
    
    private void OnMouseLeftButtonDown(object sender, RoutedEventArgs e)
    {
    }
    

    类处理程序在任何其他事件处理程序之前被调用,但它们会在整个应用程序中为指定类型的所有控件调用。因此,如果您有两个ListBoxes,那么只要在其中任何一个中单击任何ListBoxItem,都会调用此事件处理程序。

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

    【讨论】:

    • 我想补充一点。不要使用 ButtonDown 事件。使用 ButtonUp 事件。按下按钮后立即执行操作的应用程序很奇怪。而且它还有一个用户交互的原因。在基本上所有流行的应用程序中,您都可以通过在释放按钮之前将鼠标移开来取消按钮点击。
    • @StefanFabian 是的,但列表框中的项目通常在鼠标按下时被选中。并且将鼠标移开仍然可以工作。
    • @StefanFabian 我一直在尝试两个预览事件(向上和向下),我喜欢你的想法,你可以将鼠标移出控件并取消点击,但我我没有看到这种情况发生。无论我释放按钮时鼠标在哪里,都会调用我的事件(使用 System.Windows.Interaction 触发器方法)。
    • @PaulGibson hm 我认为他们做出了始终调用 up 并且仅在未取消时才单击的设计决定。因此,如果您想要取消功能,您必须自己检查鼠标是否仍在元素上方。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      您可以使用SelectionChanged事件的SelectionChangedEventArgs参数通过AddedItems和RemovedItems查找添加或删除的项目,通常只有最近点击的,如果没有,则查看最后一项是count-1 .

      【讨论】:

        【解决方案5】:

        还有另一种方式——处理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
            }
        }
        

        受到this 答案的启发,但它按名称使用列表框,我建议使用 sender 参数来避免不必要的依赖。

        【讨论】:

        • 无论如何要找到被点击的ListBoxItem的索引?
        • 到目前为止,我发现的最佳解决方案是遍历项目列表,直到找到匹配项。这适用于我的情况,因为我的列表非常小,但对于其他人来说可能无法很好地扩展。
        • 花了很多时间寻找合适的活动,但没有成功...非常感谢 Pavel!
        【解决方案6】:

        还有另一种方法可以在 ListBox 中获取 MouseDown 事件。您可以使用AddHandler 方法的handledEventsToo 签名为标记为已处理的事件添加事件处理程序:

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

        上面的第三个参数是handledEventsToo,它确保无论它是否已经被标记为HandledListBoxItem 在 ListBox 中所做的),都会调用此处理程序。
        解释见Marking Routed Events as Handled, and Class Handling
        例如,请参阅How to Attach to MouseDown Event on ListBox

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-02-01
          • 1970-01-01
          • 1970-01-01
          • 2014-10-13
          • 2011-05-01
          • 1970-01-01
          相关资源
          最近更新 更多