Подтвердить что ты не робот

Как захватить щелчок мышью по элементу в 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 - но он также не вызван.

Марк

4b9b3361

Ответ 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.