如何在 WPF 中的 ListBox 中的项目上捕获鼠标单击?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1271375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to capture a mouse click on an Item in a ListBox in WPF?
提问by marc40000
I want to get notified when an item in a ListBox gets clicked by the mouse, whether it is already selected or not.
我想在 ListBox 中的一个项目被鼠标点击时得到通知,无论它是否已经被选中。
I searched and found this: (http://kevin-berridge.blogspot.com/2008/06/wpf-listboxitem-double-click.htmlsee the comments)
我搜索并找到了这个:(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));
This works, but it does it for a DoubleClick
. I can't get it working for a single click though. I tried MouseLeftButtonDownEvent
- as there doesn't seem to be a MouseClick
event, but it's not being called.
这有效,但它可以用于DoubleClick
. 不过,我无法通过单击使其工作。我试过MouseLeftButtonDownEvent
- 因为似乎没有MouseClick
事件,但它没有被调用。
A bit more general side question: How can I see what events do exist and which handlers correspond to them and when they actually do something? For example, what tells me that for a MouseDoubleClickEvent
I need a MouseButtonEventHandler
? Maybe for a MouseLeftButtonDownEvent
I need some other handler and that's why it's not working?
一个更一般的问题:我如何才能看到哪些事件确实存在,哪些处理程序对应于它们以及它们何时实际执行某些操作?例如,是什么告诉我,对于 aMouseDoubleClickEvent
我需要 a MouseButtonEventHandler
?也许对于MouseLeftButtonDownEvent
我需要一些其他处理程序,这就是它不起作用的原因?
I also tried subclassing ListBoxItem
and override OnMouseLeftButtonDown
- but it doesn't get called either.
我也尝试过子类化ListBoxItem
和覆盖OnMouseLeftButtonDown
- 但它也没有被调用。
Marc
马克
回答by Andy
I believe that your MouseLeftButtonDown
handler is not called because the ListBox
uses this event internally to fire its SelectionChanged
event (with the thought being that in the vast majority of cases, SelectionChanged
is all you need). That said, you have a couple of options.
我相信你的MouseLeftButtonDown
处理程序没有被调用,因为它在ListBox
内部使用这个事件来触发它的SelectionChanged
事件(在绝大多数情况下,这SelectionChanged
就是你所需要的)。也就是说,你有几个选择。
First, you could subscribe to the PreviewLeftButtonDown
event instead. Most routed events have a routing strategy of Bubbling, which means that the control that generated the event gets it first, and if not handled, the event works its way up the visual tree giving each control a chance at handling the event. The Preview events, on the other hand, are Tunneling. This means that they start at the root of the visual tree (generally Window
), and work their way down to the control that generated the event. Since your code would get the chance to handle the event prior to the ListBoxItem
, this will get fired (and not be handled) so your event handler will be called. You can implement this option by replacing MouseDoubleClickEvent
in your sample with PreviewMouseLeftButtonDown
.
首先,您可以PreviewLeftButtonDown
改为订阅该事件。大多数路由事件都有冒泡的路由策略,这意味着生成事件的控件首先得到它,如果没有处理,事件会沿着可视化树向上移动,让每个控件都有机会处理事件。另一方面,预览事件是隧道。这意味着它们从可视化树的根部开始(通常是Window
),然后向下工作到生成事件的控件。由于您的代码将有机会在 之前处理事件ListBoxItem
,因此这将被触发(并且不会被处理),因此您的事件处理程序将被调用。您可以通过MouseDoubleClickEvent
在示例中替换为PreviewMouseLeftButtonDown
.
The other option is to register a class handler that will be notified whenever a ListBoxItem
fires the MouseLeftButtonDown
event. That is done like this:
另一种选择是注册一个类处理程序,该处理程序将在ListBoxItem
触发MouseLeftButtonDown
事件时收到通知。这样做是这样的:
EventManager.RegisterClassHandler(typeof(ListBoxItem),
ListBoxItem.MouseLeftButtonDownEvent,
new RoutedEventHandler(this.MouseLeftButtonDownClassHandler));
private void OnMouseLeftButtonDown(object sender, RoutedEventArgs e)
{
}
Class Handlers are called before any other event handlers, but they're called for all controls of the specified type in your entire application. So if you have two ListBoxes
, then whenever any ListBoxItem
is clicked in either of them, this event handler will be called.
类处理程序在任何其他事件处理程序之前调用,但它们是为整个应用程序中指定类型的所有控件调用的。因此,如果您有两个ListBoxes
,那么无论何时ListBoxItem
单击其中任何一个中的任何一个,都会调用此事件处理程序。
As for your second question, the best way to know what type of event handler you need for a given event, and to see the list of events available to a given control, is to use the MSDN documentation. For example, the list of all events handled by ListBoxItem
is at http://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx. If you click on the link for an event, it includes the type of the event handler for that event.
至于您的第二个问题,了解给定事件所需的事件处理程序类型以及查看给定控件可用的事件列表的最佳方法是使用 MSDN 文档。例如,处理的所有事件的列表ListBoxItem
位于http://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx。如果您单击事件的链接,它将包含该事件的事件处理程序的类型。
回答by RandomEngy
I think the first option in Andy's answer, of using PreviewMouseLeftButtonDown
, is the way to go about this. In XAML it would look like this:
我认为Andy回答中的第一个选项,使用PreviewMouseLeftButtonDown
,是解决这个问题的方法。在 XAML 中,它看起来像这样:
<ListBox Name="testListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter
Event="PreviewMouseLeftButtonDown"
Handler="ListBox_MouseLeftButtonDown" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
回答by Pavel K
There is also another way - to handle PreviewMouseDown
event and check if it was triggered by the list item:
还有另一种方法 - 处理PreviewMouseDown
事件并检查它是否由列表项触发:
In XAML:
在 XAML 中:
<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/>
In codebehind:
在代码隐藏中:
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
}
}
Was inspired by thisanswer, but it uses listbox by name, I propose to use sender argument to avoid unnecessary dependencies.
受到这个答案的启发,但它按名称使用列表框,我建议使用 sender 参数来避免不必要的依赖。
回答by zendar
There is another way to get MouseDown event in ListBox. You can add event handler for events that are marked as handled by using handledEventsToo
signature of AddHandler
method:
还有另一种方法可以在 ListBox 中获取 MouseDown 事件。您可以使用方法handledEventsToo
签名为标记为已处理的事件添加事件处理程序AddHandler
:
myListBox.AddHandler(UIElement.MouseDownEvent,
new MouseButtonEventHandler(ListBox_MouseDown), true);
Third parameter above is handledEventsToo
which ensures that this handler will be invoked no matter if it is already marked as Handled
(which ListBoxItem
does in ListBox).
See Marking Routed Events as Handled, and Class Handlingfor explanation.
See How to Attach to MouseDown Event on ListBoxfor example.
上面的第三个参数handledEventsToo
确保这个处理程序将被调用,无论它是否已经被标记为Handled
(ListBoxItem
在 ListBox 中)。
有关说明,请参阅将路由事件标记为已处理和类处理。
例如,请参见如何附加到 ListBox 上的 MouseDown 事件。
回答by elig
You can use Event="MouseLeftButtonUp"
Unlike "PreviewLeftButtonDown"
it will get the ListBoxItem handled too.
您可以使用Event="MouseLeftButtonUp"
不同,"PreviewLeftButtonDown"
它也会处理 ListBoxItem。
回答by amirhp
You can use the SelectionChangedEventArgs argument of the SelectionChanged event to find what item is add or removed through AddedItems and RemovedItems, usually only have the latest clicked on, or if not, then look at the last item which is the count-1.
您可以使用 SelectionChanged 事件的 SelectionChangedEventArgs 参数来查找通过 addedItems 和 RemovedItems 添加或删除的项目,通常只点击最新的,如果没有,则查看最后一个项目,即计数 1。