Как захватить щелчок мышью по элементу в ListBox в WPF?
Я хочу получать уведомления, когда элемент в 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));
Это работает, но делает это для DoubleClick
. Хотя я не могу заставить его работать за один клик. Я пробовал MouseLeftButtonDownEvent
- поскольку, похоже, не существует события MouseClick
, но оно не вызывается.
Еще более общий вопрос: как я могу узнать, какие события существуют и какие обработчики соответствуют им и когда они что-то делают? Например, что говорит мне, что для MouseDoubleClickEvent
мне нужен MouseButtonEventHandler
? Может быть, для a MouseLeftButtonDownEvent
мне нужен какой-то другой обработчик и почему он не работает?
Я также попытался подклассифицировать ListBoxItem
и переопределить OnMouseLeftButtonDown
- но он также не вызван.
Марк
Ответы
Ответ 1
Я считаю, что ваш обработчик 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. Если вы нажмете на ссылку для события, она включает в себя тип обработчика события для этого события.
Ответ 2
Я думаю, что Энди первым ответом на использование PreviewMouseLeftButtonDown - путь к этому. В XAML это будет выглядеть так:
<ListBox Name="testListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListBox_MouseLeftButtonDown" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Ответ 3
Существует и другой способ - обработать событие PreviewMouseDown
и проверить, был ли он вызван элементом списка:
В XAML:
<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/>
В 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
}
}
Был вдохновлен этим ответом, но он использует listbox по имени, я предлагаю использовать аргумент отправителя, чтобы избежать ненужных зависимостей.
Ответ 4
Есть другой способ получить событие MouseDown в ListBox. Вы можете добавить обработчик событий для событий, отмеченных как обработанных с помощью handledEventsToo
подписи метода AddHandler
:
myListBox.AddHandler(UIElement.MouseDownEvent,
new MouseButtonEventHandler(ListBox_MouseDown), true);
Третий параметр выше handledEventsToo
, который гарантирует, что этот обработчик будет вызван независимо от того, уже он отмечен как Handled
(который ListBoxItem
делает в ListBox).
См. Маркировка маршрутизированных событий как обработанных и обработка классов для объяснения.
См. Как подключиться к событию MouseDown в ListBox, например.
Ответ 5
Вы можете использовать аргумент SelectionChangedEventArgs события SelectionChanged, чтобы узнать, какой элемент добавляется или удаляется через AddItems и RemovedItems, как правило, только последний нажал, или если нет, то посмотрите на последний элемент, который является счетчиком-1.