2011-01-04 6 views
5

esto parece una pregunta básica, pero no puedo determinar la mejor implementación. ¿Cómo se manejan las relaciones entre dos modelos de vista y sus modelos correspondientes?Mantenimiento de MVPM de WPF Vea las relaciones de modelos y modelos

Por ejemplo, si cambió la propiedad Ocupación en PersonViewModel, ¿cómo funciona ese cambio hasta la propiedad Ocupación en el modelo de persona?

La única forma en que puedo verlo ahora es exponiendo públicamente el modelo en el modelo de vista, pero pensé que había derrotado el propósito de MVVM: desacoplando el modelo de la vista.

internal class PersonViewModel : INotifyPropertyChanged 
{ 
    private readonly PersonModel person; 

    private OccupationViewModel occupation; 

    public PersonViewModel(PersonModel person) 
    { 
     this.person = person; 
    } 

    public OccupationViewModel Occupation 
    { 
     get { return this.occupation; } 
     set 
     { 
      if (!this.occupation.Equals(value)) 
      { 
       this.occupation = value; 
       this.person.Occupation = this.occupation.Occupation; // Doesn't seem right 

       this.OnPropertyChanged(new PropertyChangedEventArgs("Occupation")); 
      } 
     } 
    } 
} 

internal class OccupationViewModel : INotifyPropertyChanged 
{ 
    public OccupationViewModel(OccupationModel occupation) 
    { 
     this.Occupation = occupation; 
    } 

    public OccupationModel Occupation { get; set; } // Is this right? 
} 

internal class PersonModel 
{ 
    public OccupationModel Occupation { get; set; } 
} 
+0

¿Por qué es PersonViewModel.Occupation una propiedad de escritura? Normalmente sería de solo lectura, después de todo, ¿quién lo configurará? –

+0

Estaba pensando en exponerlo para que algún otro modelo de vista pueda cambiarlo. ¿O es aquí donde entra algún método o comando? Por cierto, soy un novato de WPF, MVVM. – Patrick

+0

Patrick Creo que lo que Joe está diciendo es que el modelo de vista se puede modificar externamente sin configurarlo (accediendo a sus propiedades): 'personViewModel.Occupation.Occupation = new OccupationModel (" ingeniero de software ");' – Jay

Respuesta

6

Su punto de vista-modelo es desacoplar el modelo de la vista. Parece que puede estar confundiendo los conceptos de la vista y el modelo de vista.

El modelo de vista es tanto la puerta de enlace como el controlador de acceso entre los dos: determina qué hace que pase del modelo a la vista y de la vista al modelo, y de qué forma.

Puede establecer la propiedad del modelo en el setter de VM, o no. Puede guardar el estado de la vista y solo propagar esos cambios al modelo cuando el usuario hace clic en "guardar". Podría persistir ese estado en otro lugar para que alguien pueda volver y trabajar en él más antes de persistir en la vista.

El modelo de vista puede conocer el modelo íntimamente, por lo que la vista no tiene que saberlo en absoluto.

No estoy seguro de seguir su preocupación sobre la exposición pública del modelo en el modelo de vista. No lo has hecho en tu código de muestra. Ha expuesto un objeto que es el mismo tipo que usa en el modelo, pero esto es como usar int por edad tanto en el modelo como en el modelo de visualización; no ha expuesto el objeto del modelo real; usted todavía tiene control sobre si y cuándo se establece el valor en el modelo de vista en el modelo.

+0

Gracias por la clara explicación. Estaba preocupado por exponer OccupationModel en OccupationViewModel. ¿Expone públicamente el modelo en la mala práctica del modelo de vista? Estoy bajo la suposición de que el modelo debe ser encapsulado por el modelo de vista y oculto de todos los demás. – Patrick

+0

@Patrick En aplicaciones sencillas y sencillas, a veces es conveniente exponer el modelo directamente. Si está tratando con una medida de complejidad, entonces sí, es mejor transmitir todo lo que quiera exponer a través de las propiedades en el modelo de visualización. Esto es verdad más generalmente como un principio orientado a objetos, cuando se trata de composición. – Jay

0

Parece que debería exponer una propiedad 'Persona' en su PersonViewModel en lugar de exponer una propiedad de Ocupación. La propiedad Ocupación parece una capa innecesaria.

La propiedad persona se vería más abajo y la propiedad Ocupación podría ser referenciada por algo como esto 'viewModel.Person.Occupation'.

 public Person Person 
    { 
     get 
     { 
      return this.person; 
     } 
     set 
     { 
      if (!this.person.Equals(value)) 
      { 
       this.person = value; 
       this.OnPropertyChanged(new PropertyChangedEventArgs("Person")); 
      } 
     } 
    } 
5

Para mostrar las posibles relaciones entre modelo y modelo de vista que simplifica su primer ejemplo cambiando el tipo de Occupation en string. Entonces PersonModel y PersonViewModel podría tener este aspecto:

public class PersonModel : INotifyPropertyChanged 
{ 
    private string occupation; 
    public string Occupation 
    { 
    get 
    { 
     return this.occupation; 
    } 
    set 
    { 
     if (this.occupation != value) 
     { 
     this.occupation = value; 
     this.OnPropertyChanged("Occupation"); 
     } 
    } 
    } 
} 

public class PersonViewModel: INotifyPropertyChanged 
{ 
    private PersonModel model; 

    public string Occupation 
    { 
    get 
    { 
     return this.model.Occupation; 
    } 
    set 
    { 
     this.model.Occupation = value; 
    } 
    } 

    public PersonViewModel(PersonModel model) 
    { 
    this.model = model; 
    this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged); 
    } 

    private void model_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
    this.OnPropertyChanged(e.PropertyName); 
    } 
} 

La diferencia importante a su versión es que PersonModel y PersonViewModeltanto implemento INotifyPropertyChanged. Esto es importante porque, de lo contrario, cambiar una propiedad de PersonModel directamente (es decir, sin pasar por PersonViewModel) no tendrá ningún efecto en la Vista. También observe cómo el PropertyChangedEvent del Modelo se canaliza a la Vista.

Ahora supongamos Occupation no es una sino una clase string con sus propias propiedades, por ejemplo:

public class OccupationModel : INotifyPropertyChanged 
{ 
    private double salary; 
    public double Salary 
    { 
    get 
    { 
     return this.salary; 
    } 
    set 
    { 
     if (this.salary != value) 
     { 
     this.salary = value; 
     this.OnPropertyChanged("Salary"); 
     } 
    } 
    } 
} 

El uso de un modelo de vista entre su visión y modelo le da cierta flexibilidad en la forma de presentar los datos a la vista . Aquí hay dos opciones de cómo se puede hacer esto:

Opción 1 Exponer las propiedades de Occupation directamente en la PersonViewModel. Esta es una solución simple porque no necesita implementar otro ViewModel.

public class PersonViewModel: INotifyPropertyChanged 
{ 
    private PersonModel model; 

    public double OccupationSalary 
    { 
    get 
    { 
     return this.model.Occupation.Salary; 
    } 
    set 
    { 
     this.model.Occupation.Salary = value; 
    } 
    } 

    public PersonViewModel(PersonModel model) 
    { 
    this.model = model; 
    this.model.Occupation.PropertyChanged += new PropertyChangedEventHandler(occupation_PropertyChanged); 
    } 

    private void occupation_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
    this.OnPropertyChanged("Occupation" + e.PropertyName); 
    } 
} 

La propiedad OccupationSalary da acceso directo a la propiedad Salary en Occupation. Observe cómo ahora se debe manejar el evento PropertyChanged de Occupation, y que tenemos que cambiar el nombre de la propiedad en occupation_PropertyChanged.

Opción 2 (recomendado) Exponer las propiedades de Occupation a través de un OccupationViewModel. Debe hacer esto si necesita implementar cualquier lógica comercial específica al Occupation. Dada su ejemplo, esto es probablemente lo que pretende hacer:

public class PersonViewModel: INotifyPropertyChanged 
{ 
    private PersonModel model; 
    private OccupationViewModel occupationViewModel; 
    public OccupationViewModel OccupationViewModel 
    { 
    get 
    { 
     return this.occupationViewModel; 
    } 
    } 

    public PersonViewModel(PersonModel model) 
    { 
    this.model = model; 
    this.occupationViewModel = new OccupationViewModel(this.model.occupation); 
    } 
} 

public class OccupationViewModel : INotifyPropertyChanged 
{ 
    private OccupationModel model; 

    public double Salary 
    { 
    get 
    { 
     return this.model.Salary; 
    } 
    set 
    { 
     this.model.Salary = value; 
    } 
    } 

    public OccupationViewModel(OccupationModel model) 
    { 
    this.model = model; 
    this.model.PropertyChanged += new PropertyChangedEventHandler(model_PropertyChanged); 
    } 

    private void model_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
    this.OnPropertyChanged(e.PropertyName); 
    } 
} 

Como se puede ver OccupationViewModel tiene exactamente la misma estructura que el simplificada PersonViewModel he mostrado en el principio. La diferencia importante con su versión de OccupationViewModel es que expone las propiedades de OccupationModel, no OccupationModel.

+0

Upvoted para ejemplos excelentes. – bartonm

Cuestiones relacionadas