wpf simple Un buon modo per aggiornare l'associazione dati su tutte le proprietà di un ViewModel quando il modello cambia




wpf pattern (4)

Secondo i docs :

L'evento PropertyChanged può indicare che tutte le proprietà sull'oggetto sono state modificate utilizzando null o String.Empty come nome della proprietà in PropertyChangedEventArgs.

Versione breve

Se aggiorno l'oggetto Model che il mio ViewModel esegue il wrapping, quale è un buon modo per attivare notifiche di modifica delle proprietà per tutte le proprietà del modello esposte dal mio ViewModel?

Versione dettagliata

Sto sviluppando un client WPF seguendo lo schema MVVM e sto tentando di gestire gli aggiornamenti in arrivo, da un servizio, ai dati visualizzati nelle mie viste. Quando il client riceve un aggiornamento, l'aggiornamento viene visualizzato sotto forma di un DTO che utilizzo come modello.

Se questo modello è un aggiornamento a un modello esistente visualizzato nella vista, voglio che ViewModel associato aggiorni le sue proprietà di database in modo che la vista rifletta le modifiche.

Lasciatemi illustrare con un esempio. Considera il mio modello:

class FooModel
{
  public int FooModelProperty { get; set; }
}

Avvolto in un ViewModel:

class FooViewModel
{
  private FooModel _model;

  public FooModel Model 
  { 
    get { return _model; }
    set 
    { 
      _model = value; 
      OnPropertyChanged("Model"); 
    }
  }

  public int FooViewModelProperty
  {
    get { return Model.FooModelProperty; }
    set 
    {
      Model.FooModelProperty = value;
      OnPropertyChanged("FooViewModelProperty");
    }    
}

Il problema:

Quando arriva un modello aggiornato, imposto la proprietà Model ViewModel, in questo modo:

instanceOfFooVM.Model = newModel;

Ciò causa l' OnPropertyChanged("Model") , ma non di OnPropertyChanged("FooViewModelProperty") , a meno che non chiami esplicitamente quest'ultimo dal setter di Model . Pertanto, una vista associata a FooViewModelProperty non viene aggiornata per visualizzare il nuovo valore di tale proprietà quando modifico il modello.

OnPropertyChanged esplicitamente OnPropertyChanged per ogni proprietà del modello esposto non è ovviamente una soluzione desiderabile, e nessuno dei due sta prendendo il newModel e iterando attraverso le sue proprietà per aggiornare le proprietà ViewModel uno alla volta.

Qual è un approccio migliore a questo problema relativo all'aggiornamento di un intero modello e alla necessità di generare notifiche di modifica per tutte le sue proprietà esposte?


    Implements INotifyPropertyChanged
    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged 

    RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(String.Empty))

Per VB.net se qualcun altro ha bisogno. Se hai già implementato "INotifyPropertyChanged", l'ultima riga è tutto ciò di cui hai bisogno.


Un'opzione è ascoltare i tuoi eventi personali e creare una routine di supporto per aumentare le altre notifiche, se necessario.

Questo può essere semplice come aggiungere, nel tuo costruttore:

public FooViewModel()
{
    this.PropertyChanged += (o,e) =>
      {
          if (e.PropertyName == "Model")
          {
               OnPropertyChanged("FooViewModelProperty");
               // Add other properties "dependent" on Model here...
          }
      };
}

Ogni volta che la proprietà Model è impostata, iscriversi al proprio evento PropertyChanged . Quando il tuo gestore viene chiamato, spara il tuo evento PropertyChanged . Quando il Model è impostato su qualcos'altro, rimuovi il gestore dal vecchio Model .

Esempio:

class FooViewModel
{
    private FooModel _model;

    public FooModel Model 
    { 
        get { return _model; }
        set 
        { 
            if (_model != null)
            {
                _model.PropertyChanged -= ModelPropertyChanged;
            }

            if (value != null)
            {
                value.PropertyChanged += ModelPropertyChanged;
            }

            _model = value; 
            OnPropertyChanged("Model"); 
        }
    }

    public int FooViewModelProperty
    {
        get { return Model.FooModelProperty; }
        set 
        {
            Model.FooModelProperty = value;
            OnPropertyChanged("FooViewModelProperty");
        } 
    }

    private void ModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        // Here you will need to translate the property names from those
        // present on your Model to those present on your ViewModel.
        // For example:
        OnPropertyChanged(e.PropertyName.Replace("FooModel", "FooViewModel"));
    }
}




inotifypropertychanged