Esecuzione di un evento doppio clic da un object ListView WPF utilizzando MVVM

In un’applicazione WPF che utilizza MVVM, ho un controllo utente con un object listview. In fase di esecuzione, userà il databinding per riempire il listview con una collezione di oggetti.

Qual è il modo corretto di albind un evento di doppio clic agli elementi nel listview in modo che quando un elemento nella visualizzazione elenco viene fatto doppio clic, viene generato un evento corrispondente nel modello di visualizzazione e viene fatto riferimento all’elemento selezionato?

Come può essere fatto in modo pulito MVVM cioè nessun codice dietro nella vista?

Per favore, il codice dietro non è affatto una brutta cosa. Sfortunatamente, molte persone nella comunità WPF si sono sbagliate.

MVVM non è un modello per eliminare il codice. Separa la parte vista (aspetto, animazioni, ecc.) Dalla parte logica (stream di lavoro). Inoltre, è ansible testare la parte logica dell’unità.

Conosco abbastanza scenari in cui è necessario scrivere codice dietro perché l’associazione dei dati non è una soluzione a tutto. Nel tuo scenario gestirò l’evento DoubleClick nel codice dietro il file e delegherò questa chiamata al ViewModel.

Le applicazioni di esempio che utilizzano il codice dietro e soddisfano ancora la separazione MVVM possono essere trovate qui:

WPF Application Framework (WAF) – http://waf.codeplex.com

Sono in grado di farlo funzionare con .NET 4.5. Sembra semplice e nessuna terza parte o codice necessario.

                      

Mi piace usare Comandi Comandi Allegati e Comandi. Marlon Grech ha un’ottima implementazione dei Comandi di Comando Allegati. Usando questi, potremmo quindi assegnare uno stile alla proprietà ItemContainerStyle di ListView che imposterà il comando per ogni object ListViewItem.

Qui impostiamo il comando da triggersre sull’evento MouseDoubleClick e CommandParameter, sarà l’object dati su cui clicchiamo. Qui sto viaggiando sull’albero visivo per ottenere il comando che sto usando, ma potresti anche creare facilmente comandi a livello di applicazione.

  

Per i comandi, è ansible implementare direttamente un ICommand oppure utilizzare alcuni degli helper come quelli forniti in MVVM Toolkit .

Ho trovato un modo molto semplice e pulito per farlo con i trigger dell’evento SDK di Blend. Pulisci MVVM, riutilizzabile e senza code-behind.

Probabilmente hai già qualcosa del genere:

  

Ora includi un object ControlTemplate per ListViewItem come questo se non lo usi già:

        

GridViewRowPresenter sarà la radice visiva di tutti gli elementi “dentro” che compongono un elemento riga di elenco. Ora potremmo inserire un trigger per cercare gli eventi indirizzati MouseDoubleClick e chiamare un comando tramite InvokeCommandAction in questo modo:

              

Se hai elementi visivi “sopra” il GridRowPresenter (probabilmente iniziando con una griglia) puoi anche inserire il trigger qui.

Purtroppo gli eventi MouseDoubleClick non vengono generati da tutti gli elementi visivi (ad esempio, provengono da Controls, ma non da FrameworkElements). Una soluzione alternativa consiste nel derivare una class da EventTrigger e cercare MouseButtonEventArgs con un ClickCount di 2. In questo modo vengono filtrati tutti gli oggetti non MouseButtonEvents e tutti i MoseButtonEvents con ClickCount! = 2.

 class DoubleClickEventTrigger : EventTrigger { protected override void OnEvent(EventArgs eventArgs) { var e = eventArgs as MouseButtonEventArgs; if (e == null) { return; } if (e.ClickCount == 2) { base.OnEvent(eventArgs); } } } 

Ora possiamo scrivere questo (‘h’ è il Namespace della class helper sopra):

              

Mi rendo conto che questa discussione ha un anno, ma con .NET 4, ci sono pensieri su questa soluzione? Sono assolutamente d’accordo che il punto di MVVM NON è quello di eliminare un codice dietro il file. Inoltre, sento fortemente che solo perché qualcosa è complicato, non significa che sia migliore. Ecco cosa ho inserito nel codice:

  private void ButtonClick(object sender, RoutedEventArgs e) { dynamic viewModel = DataContext; viewModel.ButtonClick(sender, e); } 

È ansible utilizzare la funzione Azione di Caliburn per associare eventi ai metodi su ViewModel. Supponendo che tu abbia un metodo ItemActivated su ViewModel , il corrispondente XAML sarà simile a:

  

Per ulteriori dettagli è ansible esaminare la documentazione e i campioni di Caliburn.

Sto trovando più semplice colbind il comando quando viene creata la vista:

 var r = new MyView(); r.MouseDoubleClick += (s, ev) => ViewModel.MyCommand.Execute(null); BindAndShow(r, ViewModel); 

Nel mio caso BindAndShow assomiglia a questo (updatecontrols + avalondock):

 private void BindAndShow(DockableContent view, object viewModel) { view.DataContext = ForView.Wrap(viewModel); view.ShowAsDocument(dockManager); view.Focus(); } 

Sebbene l’approccio dovrebbe funzionare con qualsiasi metodo tu abbia di aprire nuove viste.

Ho visto la soluzione di rushui con InuptBindings ma non ero ancora in grado di colpire l’area di ListViewItem dove non c’era testo – anche dopo aver impostato lo sfondo a trasparente, quindi l’ho risolto usando diversi modelli.

Questo modello è per quando ListViewItem è stato selezionato ed è attivo:

          

Questo modello è per quando il ListViewItem è stato selezionato ed è inattivo:

      

Questo è lo stile predefinito usato per ListViewItem:

  

Quello che non mi piace è la ripetizione di TextBlock e il suo binding di testo, non lo so, posso aggirarlo dichiarandolo in un’unica posizione.

Spero che questo aiuti qualcuno!