web-dev-qa-db-fra.com

Comment capturer un clic de souris sur un élément d'un ListBox dans WPF?

Je souhaite être averti lorsqu'un élément d'un ListBox est cliqué avec la souris, qu'il soit déjà sélectionné ou non.

J'ai cherché et trouvé ceci: ( http://kevin-berridge.blogspot.com/2008/06/wpf-listboxitem-double-click.html voir les commentaires)

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

Cela fonctionne, mais il le fait pour une DoubleClick. Je ne peux pas le faire fonctionner pour un seul clic si. J'ai essayé MouseLeftButtonDownEvent - car il ne semble pas y avoir un événement MouseClick, mais il n'est pas appelé.

Question secondaire un peu plus générale: comment voir quels événements existent et quels gestionnaires leur correspondent et quand ils font réellement quelque chose? Par exemple, qu'est-ce qui me dit que pour un MouseDoubleClickEvent, j'ai besoin d'un MouseButtonEventHandler? Peut-être que pour une MouseLeftButtonDownEvent, j'ai besoin d'un autre gestionnaire et c'est pourquoi cela ne fonctionne pas?

J'ai également essayé de sous-classer ListBoxItem et de remplacer OnMouseLeftButtonDown - mais l'appel n'est pas appelé non plus.

Marc

32
marc40000

Je crois que votre gestionnaire MouseLeftButtonDown n’est pas appelé car ListBox utilise cet événement en interne pour déclencher son événement SelectionChanged (l’idée étant que, dans la grande majorité des cas, SelectionChanged est tout ce dont vous avez besoin). Cela dit, vous avez plusieurs options.

Tout d'abord, vous pouvez vous abonner à l'événement PreviewLeftButtonDown à la place. La plupart des événements routés ont une stratégie de routage de Bubbling, ce qui signifie que le contrôle qui l'a généré l'obtient en premier, et que l'événement non géré ne monte pas dans l'arborescence visuelle, donnant ainsi à chaque contrôle une chance de le gérer. Les événements de prévisualisation, par contre, sont tunneling. Cela signifie qu'ils commencent à la racine de l'arborescence visuelle (généralement Window) et descendent jusqu'au contrôle qui a généré l'événement. Etant donné que votre code aurait la possibilité de gérer l'événement avant la ListBoxItem, cette option sera renvoyée (et ne sera pas traitée) afin que votre gestionnaire d'événements soit appelé. Vous pouvez implémenter cette option en remplaçant MouseDoubleClickEvent dans votre exemple par PreviewMouseLeftButtonDown.

L'autre option consiste à enregistrer un gestionnaire de classe qui sera averti chaque fois qu'une ListBoxItem déclenchera l'événement MouseLeftButtonDown. Cela se fait comme ceci:

EventManager.RegisterClassHandler(typeof(ListBoxItem),
    ListBoxItem.MouseLeftButtonDownEvent,
    new RoutedEventHandler(this.MouseLeftButtonDownClassHandler));

private void OnMouseLeftButtonDown(object sender, RoutedEventArgs e)
{
}

Les gestionnaires de classe sont appelés avant tous les autres gestionnaires d'événements, mais ils le sont pour tous les contrôles du type spécifié dans l'ensemble de votre application. Donc, si vous avez deux ListBoxes, chaque fois que vous aurez cliqué sur ListBoxItem dans l'un d'eux, ce gestionnaire d'événements sera appelé.

Concernant votre deuxième question, le meilleur moyen de connaître le type de gestionnaire d’événements dont vous avez besoin pour un événement donné et de consulter la liste des événements disponibles pour un contrôle donné consiste à utiliser la documentation MSDN. Par exemple, la liste de tous les événements gérés par ListBoxItem se trouve dans http://msdn.Microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx . Si vous cliquez sur le lien pour un événement, il inclut le type du gestionnaire d'événements pour cet événement.

48
Andy

Je pense que la première réponse d'Andy à l'aide de PreviewMouseLeftButtonDown est le moyen d'y parvenir. En XAML, cela ressemblerait à ceci:

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

Il existe également un autre moyen - gérer l'événement PreviewMouseDown et vérifier s'il a été déclenché par l'élément de liste:

En XAML:

<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/> 

Dans 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
    }
}

A été inspiré par this answer, mais il utilise listbox par nom, je propose d’utiliser l’argument sender pour éviter les dépendances inutiles.

13
Pavel K

Il existe un autre moyen d’obtenir l’événement MouseDown dans ListBox. Vous pouvez ajouter un gestionnaire d'événements pour les événements marqués comme gérés en utilisant la signature handledEventsToo de la méthode AddHandler:

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

Le troisième paramètre ci-dessus est handledEventsToo, ce qui garantit que ce gestionnaire sera invoqué, peu importe s'il est déjà marqué Handled (ce que ListBoxItem fait dans ListBox).
Voir Marquage des événements routés comme étant gérés et gestion des classes pour des explications.
Voir Comment attacher un événement MouseDown sur ListBox par exemple.

9
zendar

Vous pouvez utiliser l'argument SelectionChangedEventArgs de l'événement SelectionChanged pour rechercher l'élément ajouté ou supprimé par les éléments AddedItems et RemovedItems. En général, seul le dernier élément sélectionné a été sélectionné, ou sinon, examinez le dernier élément qui est le compte-1.

0
amirhp

Vous pouvez utiliser Event="MouseLeftButtonUp"
Contrairement à "PreviewLeftButtonDown", le ListBoxItem sera également traité.

0
elig