MVVM: associazione a Elenco IsSelected durante il monitoraggio di IsSynchronizedWithCurrentItem

Sto monitorando le modifiche alla selezione di ListView in un design MVVM mediante l’associazione a IsSelected. Devo anche monitorare l’elemento corrente abilitando IsSynchronizedWithCurrentItem.

Trovo che quando ho due binding di ListView per la stessa collezione ottengo l’ eccezione InvalidOperationException : “La raccolta è stata modificata, l’operazione di enumerazione potrebbe non essere eseguita. ” Sembra essere un errore di sinconizzazione tra le due ListViews; uno sta triggersndo un evento PropertyChanged mentre l’altro sta aggiornando il Selettore, forse?

Non riesco a capire come ovviare a questo oltre a rinunciare all’uso di IsSynchronizedWithCurrentItem e gestirlo da solo. Qualche idea?

Grazie.

Il ViewModel e il codice dietro:

public class Item : INotifyPropertyChanged { public string Name{ get; set; } public bool IsSelected { get { return isSelected; } set { isSelected = value; OnPropertyChanged("IsSelected"); } } private bool isSelected; public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } public class ViewModel { public ViewModel() { Items = new ObservableCollection() { new Item(){Name = "Foo"}, new Item(){Name = "Bar"} }; } public ObservableCollection Items { get; private set; } } public partial class Window1 : Window { public Window1() { InitializeComponent(); DataContext = new ViewModel(); } } 

Lo XAML:

                             

Non posso offrire una soluzione diretta per il tuo problema. Tuttavia, ho una soluzione che funzionerà.

Quello che puoi fare è introdurre una seconda proprietà sul tuo View Model chiamato ‘SelectedItem’ che manterrà un riferimento all’elemento che è selezionato nel tuo ListView. Inoltre, nel modello di visualizzazione si ascolta l’evento PropertyChanged. Se il Nome proprietà associato è IsSelected, si aggiorna la proprietà SelectedItem come mittente dell’evento (l’elemento che ora ha IsSelected = true). È quindi ansible associare la proprietà SelectedItem di ListView alla proprietà con lo stesso nome della class ViewModel.

Il mio codice per la class ViewModel rivista è sotto.

 public class ViewModel : INotifyPropertyChanged { private Item _selectedItem; public ViewModel() { Items = new ObservableCollection() { new Item {Name = "Foo"}, new Item {Name = "Bar"} }; foreach ( Item anItem in Items ) { anItem.PropertyChanged += OnItemIsSelectedChanged; } } public ObservableCollection Items { get; private set; } public Item SelectedItem { get { return _selectedItem; } set { // only update if the value is difference, don't // want to send false positives if ( _selectedItem == value ) { return; } _selectedItem = value; OnPropertyChanged("SelectedItem"); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnItemIsSelectedChanged(object sender, PropertyChangedEventArgs e) { if ( e.PropertyName != "IsSelected" ) { return; } SelectedItem = sender as Item; } private void OnPropertyChanged(string propertyName) { if ( PropertyChanged != null ) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } 

Il problema sembra accadere quando si IsSelected binding a un IsSelected di un listbox e si utilizza SelectionMode='Single'

Ho scoperto che cambiando SelectionMode = 'Multiple' e poi ho aggiunto la logica al ViewModel per assicurarmi che ci fosse sempre un solo object con IsSelected impostato su true working.