Как зафиксировать щелчок мышью по элементу в 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? Может, для MouseLeftButtonDownEvent нужен другой обработчик и поэтому он не работает?

Я также пробовал создать подкласс ListBoxItem и переопределить OnMouseLeftButtonDown, но он тоже не вызывается.

Марк


person marc40000    schedule 13.08.2009    source источник
comment
Я решил обернуть каждый элемент списка кнопкой и вместо этого использовать событие кнопки. stackoverflow.com/questions/17057022 /   -  person    schedule 01.06.2017


Ответы (6)


Я считаю, что ваш MouseLeftButtonDown обработчик не вызывается, потому что ListBox использует это событие внутри себя для запуска своего SelectionChanged события (с мыслью, что в подавляющем большинстве случаев SelectionChanged - это все, что вам нужно). Тем не менее, у вас есть несколько вариантов.

Во-первых, вместо этого вы можете подписаться на событие PreviewLeftButtonDown. Большинство перенаправленных событий имеют стратегию маршрутизации «Пузыри», что означает, что элемент управления, сгенерировавший событие, получает его первым, и, если не обрабатывается, событие перемещается вверх по визуальному дереву, давая каждому элементу управления шанс обработать событие. С другой стороны, события Preview - это туннелирование. Это означает, что они начинают с корня визуального дерева (обычно 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. Если вы щелкнете ссылку для события, в ней будет указан тип обработчика этого события.

person Andy    schedule 13.08.2009
comment
Я хотел бы добавить одну вещь. НЕ используйте событие ButtonDown. Используйте событие ButtonUp. Приложения, которые делают что-то, как только вы удерживаете кнопку, просто странные. И у этого также есть причина взаимодействия с пользователем. Практически во всех популярных приложениях вы можете отменить нажатие кнопки, отведя мышь перед тем, как отпустить кнопку. - person Stefan Fabian; 14.09.2017
comment
@StefanFabian: да, но элементы в списке обычно выбираются при mousedown. И перемещение мыши по-прежнему может работать. - person Wouter; 07.02.2018
comment
@StefanFabian Я пробовал оба события предварительного просмотра (вверх и вниз), и мне нравится, что вы думаете, что с помощью вверх вы можете вывести мышь из-под контроля и отменить щелчок, но я не вижу, чтобы это произошло. Независимо от того, где находится мышь, когда я отпускаю кнопку, вызывается мое событие (с использованием метода триггеров System.Windows.Interaction). - person Paul Gibson; 25.08.2018
comment
@PaulGibson хм, я полагаю, они приняли дизайнерское решение, что up вызывается всегда и нажимается, только если он не отменен. Итак, вам нужно будет самостоятельно проверить, находится ли указатель мыши над элементом, если вам нужна функция отмены. - person Stefan Fabian; 25.08.2018

Есть и другой способ - обработать событие 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
    }
}

Был вдохновлен этим ответом, но он использует список по имени, я предлагаю использовать аргумент отправителя, чтобы избежать ненужных зависимостей.

person Pavel K    schedule 23.07.2014
comment
в любом случае, чтобы найти индекс ListBoxItem, по которому был сделан щелчок? - person ymbcKxSw; 01.06.2018
comment
Пока что лучшее решение, которое я нашел, - это перебирать список элементов, пока не найдете совпадение. Это работает в моем случае, так как у меня очень маленькие списки, но они могут плохо масштабироваться для других. - person ymbcKxSw; 04.06.2018
comment
Потратил много времени на поиски подходящего мероприятия, но безуспешно ... Большое спасибо, Павел! - person BlueDev; 13.09.2019

Я думаю, что первый вариант в ответе Энди об использовании PreviewMouseLeftButtonDown - это способ решить эту проблему. В XAML это будет выглядеть так:

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

Есть еще один способ получить событие MouseDown в ListBox. Вы можете добавить обработчик событий для событий, которые помечены как обработанные, используя подпись handledEventsToo метода AddHandler:

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

Третий параметр выше - handledEventsToo, который гарантирует, что этот обработчик будет вызываться независимо от того, помечен ли он уже как Handled (что ListBoxItem делает в ListBox).
См. Пометка перенаправленных событий как обработанных и обработка классов для объяснения.
См. Как присоединиться к событию MouseDown в ListBox например.

person zendar    schedule 25.07.2010

Вы можете использовать Event="MouseLeftButtonUp"
В отличие от "PreviewLeftButtonDown", он также будет обрабатывать ListBoxItem.

person elig    schedule 17.03.2018

Вы можете использовать аргумент SelectionChangedEventArgs события SelectionChanged, чтобы узнать, какой элемент добавляется или удаляется с помощью AddedItems и RemovedItems, обычно только последний щелчок, или, если нет, то посмотрите на последний элемент, который является count-1.

person amirhp    schedule 22.06.2015