2009-05-08 12 views
10

Tengo una pregunta sobre el diseño de MVVM para C#/WPF. He echado un vistazo a varias aplicaciones de demostración, pero realmente no manejaron mi problema. Mi aplicación consiste en objetos que contienen otros objetos. Muy parecido a una relación entre padres e hijos.Cómo presentar una colección de modelos (de vistas) en un modelo de vista

Mi pregunta ahora es:

  • hace a los niños atributo tiene que ser un modelo de vista
  • y si es así, ¿cómo puedo crear nuevos objetos principales que contienen los existente objetos secundarios 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 el ParentVM contiene el ChildVM, pero el padre real (que se encuentra dentro de la ParentVM) no tiene Niño objetos contenidos por los objetos ChildVM. Tampoco creo que sea una buena idea duplicar los objetos Child, ya que conduce a la redundancia y en mi contexto de aplicación tampoco hay necesidad/posibilidad de crear nuevos objetos Child.

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

class ParentVM { 
    Parent _parent; 

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

Sin embargo, esto significaría que habría operar directamente en el modelo si quiero manipular objetos secundarios de los ParentVM.

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

Respuesta

14

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

Luego tienes que escuche la notificación de cambio a la colección real de Parent's Children y actualice su colección ChildVMs en consecuencia.

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

Ahora también soy de la creencia de que usted debería poder exponer a la matriz directamente de ParentVM y del niño directamente desde ChildVM ya que su UI podría ser vinculante para varias propiedades en esos elementos, como su propiedad de nombre anterior. Sin embargo, los puristas de M-V-VM dirían que nunca deben hacer esto, ya que la IU nunca debería saber sobre el modelo, porque si el modelo cambia, debe cambiar la IU. Mi argumento es que si el modelo cambia, debe cambiar el ViewModel de todos modos por el mismo motivo.El único ahorro sería si hay varias vistas que comparten el mismo modelo de vista, ya que solo tendría que cambiarlo en un lugar, pero de forma realista, algo como "Nombre" no va a cambiar su "nombre" del modelo a ViewModel por lo que en esos casos no es argumento de todos modos.

Además, hay una sobrecarga de rendimiento al hacerlo de forma "purista", ya que no se puede simplemente delegar en el elemento modelo como lo hace con el nombre anterior porque la vista no conocerá ningún modelo -generado cambios a la propiedad Nombre a menos que también agregue toda la notificación de cambio adicional dentro de la máquina virtual, lo que significa que ahora tiene una notificación de cambio en el modelo cuyo único propósito es disparar una segunda notificación de cambio en la máquina virtual que luego notifica a la interfaz de usuario . ¿Puro? Sí. ¿Injerto de rendimiento? 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 vincula directamente a la propiedad ParentVM.Parent.Name, ya tendría esa notificación de cambio del modelo para notificar a la UI y también mantendrá limpia su VM para cosas que son solo específicas de VM o de Vista.

Lo que nunca hago, sin embargo, es colocar cualquier cosa en el Modelo que sea información de solo lectura. ESO para mí es para lo que es 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 el ChildVM y no en el propio Modelo, y si hay propiedades en el modelo que dictan ese color, como una propiedad de esa enumeración, en ese caso, sí, conectaría las notificaciones de cambio del modelo dentro de ChildVM. (A decir verdad, es posible que incluso sólo hacerlo a través de un convertidor de color en la interfaz de usuario directamente, siendo la unión a la enumeración del modelo. Es realmente una cosa de caso por caso.)

HTH,

Marcos

1

Muy bien, recibí un poco de ayuda y consejo de un foro de .NET: Resolveré el problema proporcionando un método de obtención para el modelo dentro del modelo de vista. Entonces, si creo un nuevo Parent con ChildVMs existentes, solo devuelvo la referencia Child dentro de los ChildVM y los asigno a mi nuevo Parent.

+1

Hola, Torsten (@Torsten) y admito por completo que esto es parcial, pero ya que marcó su propia respuesta como la aceptada usando lo mismo que ya he mencionado en mi respuesta, y también proporcionó el por qué, cambiando mi mente por lo que obtener el aceptar? No puede darse puntos de todos modos y como puede ver, otros aprecian mi descripción aquí explicando por qué está bien exponer el modelo de ViewModel. ¡Gracias! – MarqueIV

+1

@MarqueIV Creo que marqué mi respuesta como la solución ya que tu respuesta llegó más tarde que la mía. También veo que yo misma cambié tu respuesta, así que aquí tienes. – Torsten

+0

Gracias! ¡Muy apreciado! :) – MarqueIV

Cuestiones relacionadas