WPF Vincola gli eventi dell’interfaccia utente ai comandi in ViewModel

Sto facendo un refactoring di una semplice applicazione per seguire MVVM e la mia domanda è: come faccio a spostare un evento SelectionChanged dal mio codice dietro a viewModel? Ho esaminato alcuni esempi di elementi vincolanti per i comandi, ma non l’ho capito bene. Qualcuno può aiutare con questo. Grazie!

Qualcuno può fornire una soluzione usando il codice qui sotto? Grazie molto!

public partial class MyAppView : Window { public MyAppView() { InitializeComponent(); this.DataContext = new MyAppViewModel (); // Insert code required on object creation below this point. } private void contactsList_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e) { //TODO: Add event handler implementation here. //for each selected contact get the labels and put in collection ObservableCollection contactListLabels = new ObservableCollection(); foreach (ContactListModel contactList in contactsList.SelectedItems) { foreach (AggregatedLabelModel aggLabel in contactList.AggLabels) { contactListLabels.Add(aggLabel); } } //aggregate the contactListLabels by name ListCollectionView selectedLabelsView = new ListCollectionView(contactListLabels); selectedLabelsView.GroupDescriptions.Add(new PropertyGroupDescription("Name")); tagsList.ItemsSource = selectedLabelsView.Groups; } } 

È necessario utilizzare EventTrigger in combinazione con InvokeCommandAction dallo spazio dei nomi Windows.Interactivity. Ecco un esempio:

        

È ansible fare riferimento a System.Windows.Interactivity andando su Add reference > Assemblies > Extensions .

E lo spazio dei nomi completo è: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" .

Questa domanda ha un problema simile.

WPF MVVM: i comandi sono semplici. Come colbind View e ViewModel con RoutedEvent

Il modo in cui ho a che fare con questo problema è di avere una proprietà SelectedItem nel ViewModel, e quindi associare il SelectedItem del tuo ListBox o qualsiasi altra cosa a quella proprietà.

La cosa migliore è usare Windows.Interactivity . Utilizzare EventTriggers per colbind un ICommand a qualsiasi RoutedEvent .

Ecco un articolo per iniziare: Silverlight e WPF Behaviors and Triggers

Per refactoring è necessario spostare il tuo pensiero. Non gestirai più un evento “selezione modificata”, ma piuttosto memorizzando l’elemento selezionato nel tuo modello view. Dovresti quindi utilizzare l’associazione dati bidirezionale in modo che quando l’utente seleziona un elemento, il tuo modello di vista sia aggiornato e quando cambi l’elemento selezionato, lo visualizzi aggiornato.

   

Comando

{eb: EventBinding} (schema di denominazione semplice per trovare il comando)

{eb: EventBinding Command = CommandName}

CommandParameter

$ e (EventAgrs)

$ this o $ this.Property

stringa

https://github.com/JonghoL/EventBindingMarkup

Seguirò la risposta più alta in questa domanda

Fondamentalmente il tuo modello di vista conterrà un elenco di tutti i tuoi articoli e un elenco di elementi selezionati. È quindi ansible albind un comportamento alla listbox che gestisce l’elenco degli elementi selezionati.

Ciò significa che non hai nulla nel codice e che lo xaml è abbastanza facile da seguire, inoltre il comportamento può essere riutilizzato altrove nella tua app.

  

A volte la soluzione dell’evento di binding da comandare tramite il trigger di Interattività non funziona, quando è necessario associare l’evento di usercontrol personalizzato. In questo caso puoi usare un comportamento personalizzato.

Dichiarare un comportamento di binding come:

 public class PageChangedBehavior { #region Attached property public static ICommand PageChangedCommand(DependencyObject obj) { return (ICommand)obj.GetValue(PageChangedCommandProperty); } public static void SetPageChangedCommand(DependencyObject obj, ICommand value) { obj.SetValue(PageChangedCommandProperty, value); } public static readonly DependencyProperty PageChangedCommandProperty = DependencyProperty.RegisterAttached("PageChangedCommand", typeof(ICommand), typeof(PageChangedBehavior), new PropertyMetadata(null, OnPageChanged)); #endregion #region Attached property handler private static void OnPageChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var control = d as PageControl; if (control != null) { if (e.NewValue != null) { control.PageChanged += PageControl_PageChanged; } else { control.PageChanged -= PageControl_PageChanged; } } } static void PageControl_PageChanged(object sender, int page) { ICommand command = PageChangedCommand(sender as DependencyObject); if (command != null) { command.Execute(page); } } #endregion 

}

E poi legalo al comando in xaml:

    

Come cita @Cameron MacFarland, vorrei semplicemente associare due vie a una proprietà su viewModel. Nel setter della proprietà è ansible eseguire qualsiasi logica richiesta, ad esempio aggiungendo a un elenco di contatti, in base alle proprie esigenze.

Tuttavia, non chiamerei necessariamente la proprietà ‘SelectedItem’ come viewModel non dovrebbe conoscere il livello di visualizzazione e come interagisce con le sue proprietà. Lo chiamerei qualcosa come CurrentContact o qualcosa del genere.

Ovviamente questo è meno che non si voglia solo creare comandi come esercizio per esercitarsi, ecc.