2009-08-13 10 views
28

Je souhaite recevoir une notification lorsqu'un élément d'un contrôle ListBox est cliqué à la souris, qu'il soit déjà sélectionné ou non.Comment capturer un clic de souris sur un élément dans un ListBox dans WPF?

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 un DoubleClick. Je ne peux pas le faire fonctionner pour un seul clic si. J'ai essayé MouseLeftButtonDownEvent - comme il ne semble pas y avoir un événement MouseClick, mais il n'est pas appelé. Question un peu plus générale: Comment puis-je voir quels événements existent et quels gestionnaires les correspondent et quand ils font réellement quelque chose? Par exemple, ce qui me dit que pour un MouseDoubleClickEvent j'ai besoin d'un MouseButtonEventHandler? Peut-être que pour un MouseLeftButtonDownEvent j'ai besoin d'un autre gestionnaire et c'est pourquoi ça ne fonctionne pas?

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

Marc

+0

J'ai choisi d'enrober chaque listbox avec le bouton et d'utiliser plutôt l'événement button. https://stackoverflow.com/questions/17057022/getting-listbox-item-index-from-button-click – Dummy

Répondre

43

Je crois que votre gestionnaire MouseLeftButtonDown n'est pas appelé parce que le ListBox utilise cet événement en interne pour tirer son événement SelectionChanged (avec la pensée étant que dans la grande majorité des cas, SelectionChanged est tout ce dont vous avez besoin). Cela dit, vous avez quelques options. 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 a généré l'événement l'obtient en premier, et qu'il ne gère pas l'événement qui gravite l'arbre visuel donnant à chaque contrôle une chance de gérer l'événement. Les événements Aperçu, d'autre part, sont Tunneling. Cela signifie qu'ils commencent à la racine de l'arbre visuel (généralement Window), et descendent jusqu'au contrôle qui a généré l'événement. Puisque votre code aurait la chance de gérer l'événement avant le ListBoxItem, il sera déclenché (et ne sera pas géré) pour 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'un ListBoxItem déclenche 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) 
{ 
} 

Handlers de classe sont appelés avant tout autre gestionnaire d'événements, mais ils sont appelés pour tous les contrôles du type spécifié dans votre application entière. Donc, si vous avez deux ListBoxes, chaque fois que l'on clique sur ListBoxItem dans l'un d'entre eux, ce gestionnaire d'événements sera appelé. En ce qui concerne votre deuxième question, la meilleure façon de savoir quel type de gestionnaire d'événements vous avez besoin pour un événement donné et de voir la liste des événements disponibles pour un contrôle donné est d'utiliser la documentation MSDN. Par exemple, la liste de tous les événements gérés par ListBoxItem est au http://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx. Si vous cliquez sur le lien d'un événement, il inclut le type du gestionnaire d'événements pour cet événement.

+1

Lordy, c'est une bonne réponse! –

+1

Une chose, j'aimerais ajouter. N'utilisez PAS l'événement ButtonDown. Utilisez l'événement ButtonUp. Les applications qui font des choses dès que vous maintenez le bouton enfoncé sont tout simplement bizarres. Et il a aussi une raison d'interaction de l'utilisateur. Dans la plupart des applications populaires, vous pouvez annuler les clics sur les boutons en éloignant la souris avant de relâcher le bouton. –

+0

@StefanFabian yes mais les éléments dans une listbox sont normalement sélectionnés sur mousedown. Et déplacer la souris peut toujours fonctionner. – Wouter

13

Je pense que la première réponse d'Andy à l'utilisation de PreviewMouseLeftButtonDown est la façon de procéder.En XAML, il ressemblerait à ceci:

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

Il existe une autre façon d'obtenir l'événement MouseDown dans ListBox. Vous pouvez ajouter gestionnaire d'événements pour les événements qui sont marqués comme traités en utilisant la signature handledEventsToo de AddHandler méthode:

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

Le troisième paramètre ci-dessus est handledEventsToo qui assure que ce gestionnaire sera appelé peu importe si elle est déjà marquée comme Handled (ce que fait ListBoxItem dans ListBox).
Voir Marking Routed Events as Handled, and Class Handling pour l'explication. Voir How to Attach to MouseDown Event on ListBox par exemple.

9

Il y a aussi une autre façon - pour gérer l'événement PreviewMouseDown et vérifier si elle a été déclenchée par l'élément de liste:

En XAML:

<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/> 

En behind:

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 réponse, mais il utilise la liste par nom, je propose d'utiliser l'argument de l'expéditeur à un annuler les dépendances inutiles.

0

Vous pouvez utiliser l'argument SelectionChangedEventArgs de l'événement SelectionChanged pour trouver quel élément est ajouté ou supprimé via AddedItems et RemovedItems, en général, cliquez sur le dernier en cours ou, sinon, regardez le dernier élément qui est le compte. 1.