Pregunta

Tengo una pregunta sobre el diseño MVVM para C # / WPF. He echado un vistazo a varias aplicaciones de demostración, pero en realidad no manejaron mi problema. Mi aplicación consta de objetos que contienen otros objetos. Al igual que en una relación entre padres e hijos.

Mi pregunta ahora es:

  • ¿el atributo secundario tiene que ser un ViewModel?
  • y si es así, ¿cómo creo nuevos objetos principales, que contienen los objetos secundarios existentes a través de ViewModels?

Tengo algo como el siguiente escenario:

class Child {
    string Name;
}

class ChildVM {
    Child _child;
    string Name{return _child.Name;}
}

class Parent {
    string Name;
    List<Child> children;
}

class ParentVM{
    Parent _parent;

    string Name{return _parent.Name;}
    List<ChildVM> children {get;set;}

    ParentVM(Parent p){_parent = p;}
}

void CreateANewParent(){
    List<ChildVM> children = new List<ChildVM>(){new ChildVM(new Child()),...};
    ParentVM parent = new ParentVM(new Parent());
    foreach(ChildVM child in children)
        parent.children.Add(child);
}

El problema aquí es que ParentVM contiene ChildVM, PERO el Parent real (que está dentro de ParentVM) no tiene los objetos Child contenidos en los objetos ChildVM. Tampoco creo que sea una buena idea duplicar los objetos secundarios, ya que conduce a la redundancia y en el contexto de mi aplicación tampoco hay necesidad / posibilidad de crear nuevos objetos secundarios.

También pensé en el siguiente diseño de clase:

class ParentVM {
    Parent _parent;

    string Name{return _parent.Name;}
    List<Child> children {get{return _parent.Children;}}
}

Sin embargo, esto significaría que operaría directamente en el Modelo si quiero manipular un objeto Child de ParentVM.

Por otro lado, simplemente podría dejar el padre (Modelo) en blanco y usar ParentVM para crear un nuevo padre en la base de datos. ¿Pero es esta una buena forma de manejar el problema?

¿Fue útil?

Solución

En realidad, la forma correcta de hacerlo es cuando crea un ParentVM por primera vez, itera a través de los elementos secundarios del elemento primario que se pasa, crea un ChildVM para cada uno y luego agrega esos objetos ChildVM a la propiedad ChildVM de ParentVM. (Algunos simplemente llamarían a esa propiedad 'Hijos', pero personalmente me gusta aclarar que es una colección de ChildVMs, no una colección de objetos Child. Simplemente agregar el sufijo 'VM' lo deja muy claro.

También debe escuchar la notificación de cambio a la colección actual de Parent's Children y actualizar su colección ChildVMs en consecuencia.

De esa manera, tiene un modelo con Parent- > Children- > Child y un ViewModel de ParentVM- > ChildVMs- > ChildVM, que creo que es exactamente lo que quiere.

Ahora también creo que debería poder exponer al padre directamente desde el ParentVM, así como al niño directamente desde el ChildVM, ya que su interfaz de usuario podría estar vinculada a varias propiedades en esos elementos, como su nombre propiedad arriba. Sin embargo, los puristas de M-V-VM dirían que nunca hagas esto diciendo que la interfaz de usuario nunca debe saber sobre el modelo porque si el modelo cambia, tienes que cambiar la interfaz de usuario. Mi argumento es que si el modelo cambia, debe cambiar el ViewModel de todos modos por la misma razón. El único ahorro sería si hay varias vistas que comparten el mismo ViewModel, ya que solo tendría que cambiarlo en un solo lugar, pero de manera realista, algo como 'Nombre' no va a cambiar su '' nombre ''. del modelo al ViewModel, por lo que en esos casos no es un argumento de todos modos.

Además, hay una sobrecarga de rendimiento al hacerlo de manera 'purista' en el sentido de que no puede simplemente delegar al elemento del modelo como lo está haciendo con el Nombre anterior porque la vista nunca sabrá sobre ningún modelo- generó cambios en la propiedad Nombre a menos que también agregue todas las notificaciones de cambio adicionales dentro de la VM, lo que significa que ahora tiene una notificación de cambio en el modelo cuyo único propósito es disparar una notificación de cambio de segundo en la VM que luego notifica a la IU. ¿Puro? Sí. ¿Invasor invasivo? Usted apuesta, especialmente cuando se están produciendo grandes cantidades de cambios y está utilizando la interfaz INotifyPropertyChanged porque eso significa que tiene que hacer comparaciones de cadenas en el controlador de cambios para detectar y delegar todos esos cambios. Sin embargo, si se une directamente a la propiedad ParentVM.Parent.Name, ya tendría esa notificación de cambio del modelo para notificar a la IU y también mantendrá su VM limpia para cosas que son solo específicas de VM o View.

Sin embargo, lo que nunca hago es colocar algo en el Modelo que sea información de solo lectura. ESO para mí es para qué es el ViewModel. Entonces, por ejemplo, si los niños tienen un color específico basado en una enumeración o lo que sea, eso para mí es algo que va en ChildVM y no en el Modelo en sí, y si hay alguna propiedad en el modelo que dicta ese color, como un propiedad de esa enumeración, en ese caso, sí, conectaría las notificaciones de cambio del modelo dentro de ChildVM. (A decir verdad, incluso puedo hacerlo a través de un convertidor de color en la interfaz de usuario directamente, aún vinculante a la enumeración del modelo. Realmente es una cuestión de caso por caso).

HTH,

Marcar

Otros consejos

Muy bien, obtuve ayuda y consejos de un foro .NET: Resolveré el problema proporcionando un Método Get para el Modelo dentro del ViewModel. Entonces, si creo un nuevo Parent con ChildVMs existentes, simplemente devuelvo la referencia Child dentro de ChildVMs y los asigno a mi nuevo Parent.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top