2009-08-13 9 views
28

Ich möchte benachrichtigt werden, wenn ein Element in einer ListBox mit der Maus angeklickt wird, ob es bereits ausgewählt ist oder nicht.Wie man einen Mausklick auf ein Element in einer ListBox in WPF erfasst?

Ich suchte und fand diese: (http://kevin-berridge.blogspot.com/2008/06/wpf-listboxitem-double-click.html die Kommentare sehen)

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

Dies funktioniert, aber es macht es für einen DoubleClick. Ich kann es nicht für einen einzigen Klick funktionieren. Ich habe versucht, MouseLeftButtonDownEvent - da scheint es kein MouseClick Ereignis, aber es wird nicht aufgerufen.

Eine etwas allgemeinere Frage: Wie kann ich sehen, welche Ereignisse existieren und welche Handler ihnen entsprechen und wann sie tatsächlich etwas tun? Zum Beispiel, was sagt mir, dass ich für eine MouseDoubleClickEvent brauche ich eine MouseButtonEventHandler? Vielleicht brauche ich für einen MouseLeftButtonDownEvent einen anderen Handler und deshalb funktioniert es nicht?

Ich versuchte auch Unterklasse ListBoxItem und überschreiben OnMouseLeftButtonDown - aber es wird auch nicht aufgerufen.

Marc

+0

Ich habe gewählt, jedes listboxitem mit Knopf zu wickeln und Knopf Ereignis stattdessen zu benutzen. https://stackoverflow.com/questions/17057022/getting-listbox-item-index-from-button-click – Dummy

Antwort

43

Ich glaube, dass Ihre MouseLeftButtonDown Handler nicht da aufgerufen wird die ListBox dieses Ereignis verwendet intern sein SelectionChanged Ereignis ausgelöst (mit dem Gedanken, dass die Fälle in der überwiegenden Mehrheit ist, SelectionChanged alles, was Sie benötigen). Das heißt, Sie haben ein paar Möglichkeiten.

Zunächst können Sie stattdessen das Ereignis PreviewLeftButtonDown abonnieren. Die meisten Routingereignisse haben eine Routinstrategie von Bubbling, was bedeutet, dass das Steuerelement, das das Ereignis generiert hat, es zuerst erhält und das Ereignis nicht den visuellen Baum bearbeitet, sodass jedes Steuerelement eine Chance hat, das Ereignis zu verarbeiten. Die Preview-Ereignisse hingegen sind Tunneling. Dies bedeutet, dass sie am Stamm des visuellen Baums beginnen (im Allgemeinen Window) und sich zu dem Steuerelement hinabarbeiten, das das Ereignis generiert hat. Da Ihr Code die Möglichkeit hat, das Ereignis vor dem ListBoxItem zu behandeln, wird dies ausgelöst (und nicht behandelt), sodass Ihr Ereignishandler aufgerufen wird. Sie können diese Option implementieren, indem Sie MouseDoubleClickEvent in Ihrem Beispiel durch PreviewMouseLeftButtonDown ersetzen.

Die andere Option besteht darin, einen Klassenhandler zu registrieren, der benachrichtigt wird, wenn ein ListBoxItem das Ereignis MouseLeftButtonDown auslöst. Das wird so gemacht:

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

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

Klasse Handlers vor allen anderen Ereignishandler aufgerufen werden, aber sie sind für alle Bedienelemente des angegebenen Typs in Ihrer gesamten Anwendung aufgerufen. Wenn Sie also zwei ListBoxes haben, dann wird, wenn in einem von ihnen auf ListBoxItem geklickt wird, dieser Event-Handler aufgerufen.

Was Ihre zweite Frage betrifft, sollten Sie die MSDN-Dokumentation verwenden, um zu erfahren, welche Art von Ereignisbehandler Sie für ein bestimmtes Ereignis benötigen und welche Liste der für ein bestimmtes Steuerelement verfügbaren Ereignisse verfügbar ist. Die Liste aller Ereignisse, die von ListBoxItem behandelt werden, befindet sich beispielsweise um http://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx. Wenn Sie auf den Link für ein Ereignis klicken, enthält es den Typ des Ereignishandlers für dieses Ereignis.

+1

Herr, das ist eine gute Antwort! –

+1

Eine Sache möchte ich hinzufügen. Verwenden Sie das Ereignis ButtonDown NICHT. Verwenden Sie das Ereignis ButtonUp. Anwendungen, die Dinge tun, sobald Sie den Knopf gedrückt halten, sind nur komisch. Und es hat auch einen Benutzerinteraktionsgrund. In praktisch allen gängigen Anwendungen können Sie die Tastenklicks abbrechen, indem Sie die Maustaste loslassen, bevor Sie die Taste loslassen. –

+0

@StefanFabian ja, aber Elemente in einer Listbox werden normalerweise auf mousedown ausgewählt. Und das Bewegen der Maus kann immer noch funktionieren. – Wouter

13

Ich denke Andys erste Antwort der Verwendung von PreviewMouseLeftButtonDown ist der Weg, um darüber zu gehen.In XAML würde es so aussehen:

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

Es gibt eine andere Möglichkeit, MouseDown-Ereignis in ListBox zu erhalten. Sie können für Veranstaltungen Event-Handler hinzufügen, die mithilfe von handledEventsToo Signatur von AddHandler Verfahren als erledigt gekennzeichnet sind:

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

dritter Parameter über handledEventsToo ist, die sicherstellt, dass diese Handler egal aufgerufen werden, wenn sie bereits als Handled markiert (was ListBoxItem in ListBox tut).
Siehe Marking Routed Events as Handled, and Class Handling für Erklärung.
Siehe zum Beispiel How to Attach to MouseDown Event on ListBox.

9

Es gibt auch eine andere Art und Weise - PreviewMouseDown Ereignis zu behandeln und prüfen, ob es durch das Listenelement ausgelöst wurde:

In XAML:

<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/> 

In Code-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 
    } 
} 

Wurde von this Antwort inspiriert, aber es verwendet Listbox nach Name, ich schlage vor, Sender Argument zu verwenden Nötige unnötige Abhängigkeiten.

0

Sie können das SelectionChangedEventArgs-Argument des SelectionChanged-Ereignisses verwenden, um zu ermitteln, welches Element über AddedItems und RemovedItems hinzugefügt oder entfernt wird. In der Regel wird nur das letzte angeklickt, oder wenn nicht, dann das letzte Element anzeigen. 1.