2009-08-13 9 views
28

Desidero ricevere una notifica quando un oggetto in una ListBox viene cliccato con il mouse, sia che sia già selezionato o meno.Come catturare un clic del mouse su un oggetto in un ListBox in WPF?

Ho cercato e trovato questo: (http://kevin-berridge.blogspot.com/2008/06/wpf-listboxitem-double-click.html si vedano i commenti)

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

Questo funziona, ma lo fa per un DoubleClick. Non riesco a farlo funzionare per un solo clic però. Ho provato MouseLeftButtonDownEvent - in quanto non sembra essere un evento MouseClick, ma non viene chiamato.

Una domanda un po 'più generale: come posso vedere quali eventi esistono e quali gestori corrispondono a loro e quando effettivamente fanno qualcosa? Ad esempio, cosa mi dice che per un MouseDoubleClickEvent ho bisogno di un MouseButtonEventHandler? Forse per un MouseLeftButtonDownEvent ho bisogno di qualche altro gestore ed è per questo che non funziona?

Ho anche provato la sottoclasse ListBoxItem e l'override OnMouseLeftButtonDown - ma non viene chiamato neanche.

Marc

+0

Ho scelto di avvolgere ogni listboxitem con il pulsante e utilizzare invece l'evento button. https://stackoverflow.com/questions/17057022/getting-listbox-item-index-from-button-click – Dummy

risposta

43

credo che il tuo gestore MouseLeftButtonDown non viene chiamato in quanto il ListBox utilizza questo evento interno al fuoco suo evento SelectionChanged (con il pensiero è che nella stragrande maggioranza dei casi, SelectionChanged è tutto ciò che serve). Detto questo, hai un paio di opzioni.

In primo luogo, è possibile iscriversi invece all'evento PreviewLeftButtonDown. La maggior parte degli eventi indirizzati ha una strategia di routing di Bubbling, il che significa che il controllo che ha generato l'evento lo ottiene per primo, e non ha gestito l'evento che si sviluppa lungo l'albero visivo dando a ciascun controllo la possibilità di gestire l'evento. Gli eventi di anteprima, d'altra parte, sono Tunneling. Ciò significa che iniziano alla radice dell'albero visivo (generalmente Window) e si dirigono verso il controllo che ha generato l'evento. Dato che il tuo codice avrà la possibilità di gestire l'evento prima dello ListBoxItem, questo verrà generato (e non verrà gestito) in modo che il gestore di eventi venga chiamato. Puoi implementare questa opzione sostituendo MouseDoubleClickEvent nel tuo campione con PreviewMouseLeftButtonDown.

L'altra opzione è registrare un gestore di classe che verrà avvisato ogni volta che un ListBoxItem attiva l'evento MouseLeftButtonDown. Questo viene fatto in questo modo:

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

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

gestori di classe sono chiamate prima di qualsiasi altra gestori di eventi, ma si chiamano per tutti i controlli del tipo specificato nella vostra intera applicazione. Quindi se hai due ListBoxes, allora ogni volta che si fa clic su uno qualsiasi di ListBoxItem, verrà chiamato questo gestore di eventi.

Per quanto riguarda la seconda domanda, il modo migliore per sapere quale tipo di gestore di eventi è necessario per un dato evento e per visualizzare l'elenco di eventi disponibili per un determinato controllo è utilizzare la documentazione MSDN. Ad esempio, l'elenco di tutti gli eventi gestiti da ListBoxItem è http://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx. Se fai clic sul link per un evento, include il tipo di gestore eventi per quell'evento.

+1

Lordy, questa è una buona risposta! –

+1

Una cosa, vorrei aggiungere. NON usare l'evento ButtonDown. Usa l'evento ButtonUp. Le applicazioni che fanno cose non appena si tiene premuto il pulsante sono semplicemente strane. E ha anche un motivo di interazione dell'utente. In pratica in tutte le applicazioni più diffuse è possibile annullare i clic del tasto spostando il mouse prima di rilasciare il pulsante. –

+0

@StefanFabian yes ma gli elementi in una listbox vengono normalmente selezionati su mouse. E spostare via il mouse può ancora funzionare. – Wouter

13

Penso che la prima risposta di Andy all'uso di PreviewMouseLeftButtonDown sia la soluzione.In XAML sarebbe simile a questa:

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

C'è un altro modo per ottenere evento MouseDown in ListBox. È possibile aggiungere gestore di eventi per gli eventi che sono contrassegnate come gestite utilizzando handledEventsToo firma del AddHandler metodo:

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

terzo parametro di cui sopra è handledEventsToo che assicura che questo gestore verrà richiamato non importa se si è già contrassegnata come Handled (quale ListBoxItem fa in ListBox).
Vedere Marking Routed Events as Handled, and Class Handling per la spiegazione.
Vedere How to Attach to MouseDown Event on ListBox per esempio.

9

C'è anche un altro modo - per gestire PreviewMouseDown evento e verificare se è stato attivato dalla voce dell'elenco:

In XAML:

<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/> 

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

È stato ispirato dalla risposta this, ma usa listbox per nome, propongo di usare l'argomento mittente per un annullare le dipendenze non necessarie.

0

È possibile utilizzare l'argomento SelectionChangedEventArgs dell'evento SelectionChanged per individuare l'elemento da aggiungere o rimuovere tramite AddedItems e RemovedItems, in genere solo l'ultimo clic su, oppure in caso contrario, quindi esaminare l'ultimo elemento che è il numero- 1.

Problemi correlati