vista ventajas patrones patron mvvc mvc modelo entre ejemplo diseƱo diferencias desventajas arquitectura wpf data-binding mvvm inotifypropertychanged

wpf - ventajas - patrones mvc mvvm



Una buena forma de actualizar el enlace de datos en todas las propiedades de un ViewModel cuando el Modelo cambie (4)

Version corta

Si actualizo el objeto Modelo que mi ViewModel ajusta, ¿cuál es una buena manera de activar las notificaciones de cambio de propiedad para todas las propiedades del modelo que mi ViewModel expone?

Versión detallada

Estoy desarrollando un cliente WPF siguiendo el patrón MVVM, y estoy tratando de manejar las actualizaciones entrantes, desde un servicio, hasta los datos que se muestran en mis vistas. Cuando el cliente recibe una actualización, la actualización aparece en forma de DTO que utilizo como modelo.

Si este modelo es una actualización de un modelo existente que se muestra en la Vista, quiero que ViewModel asociado actualice sus propiedades de datos para que la Vista refleje los cambios.

Déjame ilustrar con un ejemplo. Considera mi Modelo:

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

Envuelto en 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"); } }

El problema:

Cuando llega un modelo actualizado, configuro la propiedad Model de ViewModel, así:

instanceOfFooVM.Model = newModel;

Esto hace que OnPropertyChanged("Model") se OnPropertyChanged("FooViewModelProperty") , pero no OnPropertyChanged("FooViewModelProperty") , a menos que llame a este último explícitamente desde el setter del Model . Por lo tanto, una Vista vinculada a FooViewModelProperty no se actualizará para mostrar el nuevo valor de esa propiedad cuando modifique el Modelo.

OnPropertyChanged explícitamente a OnPropertyChanged para cada propiedad expuesta del Modelo obviamente no es una solución deseable, y tampoco está tomando newModel e iterando a través de sus propiedades para actualizar las propiedades de ViewModel una a una.

¿Cuál es un mejor enfoque para este problema de actualización de un modelo completo y la necesidad de disparar notificaciones de cambio para todas sus propiedades expuestas?


De acuerdo con los docs :

El evento PropertyChanged puede indicar que todas las propiedades del objeto han cambiado usando null o String.Empty como nombre de propiedad en PropertyChangedEventArgs.


Siempre que su propiedad de Model esté configurada, suscríbase a su propio evento PropertyChanged . Cuando se llama a su controlador, active su propio evento PropertyChanged . Cuando el Model está configurado para otra cosa, retire su controlador del Model .

Ejemplo:

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


Una opción es escuchar tus propios eventos y hacer una rutina de ayuda para plantear las otras notificaciones según sea necesario.

Esto puede ser tan simple como agregar, en tu constructor:

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


Implements INotifyPropertyChanged Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(String.Empty))

Para VB.net si alguien más lo necesita. Si ya ha implementado "INotifyPropertyChanged", la última línea es todo lo que necesita.