2010-04-05 21 views
17

He estado experimentando con el patrón de MVVM mencionado anteriormente y he estado teniendo dificultades para definir límites claros en algunos casos. En mi aplicación, tengo un diálogo que me permite crear una conexión a un controlador. Hay una clase ViewModel para el diálogo, que es bastante simple. Sin embargo, el cuadro de diálogo también alberga un control adicional (elegido por ContentTemplateSelector), que varía según el tipo particular de Controlador que se está conectando. Este control tiene su propio ViewModel.MVVM: ¿Cómo manejar la interacción entre ViewModels anidados?

El problema que me surge es que, cuando cierro el cuadro de diálogo presionando OK, necesito crear realmente la conexión solicitada, que requiere información capturada en la clase interna ViewModel específica del controlador. Es tentador simplemente tener todas las clases de ViewModel específicas del controlador implementando una interfaz común que construye la conexión, pero ¿el ViewModel interno realmente debería estar a cargo de esta construcción?

Mi pregunta general es: ¿hay patrones de diseño generalmente aceptados sobre cómo los Modelos de Vista deberían interactuar entre ellos, particularmente cuando una VM "padre" necesita ayuda de una VM "infantil" para saber qué hacer?


EDIT:

Yo he venido para arriba con un diseño que es un poco más limpio que estaba pensando en un principio, pero todavía no estoy seguro de si es la manera 'correcta' de hacerlo. Tengo algunos servicios de back-end que permiten que ContentTemplateSelector mire una instancia de Controller y pseudo-mágicamente encuentre un control para mostrar para el constructor de conexiones. Lo que me molestaba acerca de esto es que mi ViewModel de nivel superior tendría que mirar el DataContext para el control generado y convertirlo a una interfaz adecuada, lo que parece una mala idea (¿por qué la View DataContext tiene algo que ver con la creación ? la conexión)

terminé con algo como esto (simplificar):

public interface IController 
{ 
    IControllerConnectionBuilder CreateConnectionBuilder(); 
} 

public interface IControllerConnectionBuilder 
{ 
    ControllerConnection BuildConnection(); 
} 

tengo mi clase de modelo de vista interno implementar IControllerConnectionBuilder y el controlador devuelve el modelo de vista interno. El ViewModel de nivel superior luego visualiza este IControllerConnectionBuilder (a través del mecanismo pseudo-mágico). Todavía me molesta un poco que sea mi ViewModel interno la realización del edificio, pero al menos ahora mi ViewModel de nivel superior no tiene que saber acerca de los detalles sucios (ni siquiera sabe o le importa que el control visualizado está utilizando un ViewModel).

Acepto pensamientos adicionales si hay formas de limpiar esto más. Todavía no está claro cuánta responsabilidad está 'bien' para que ViewModel tenga.

+2

Nos hacemos este tipo de preguntas constantemente en mi trabajo. Has formulado esta pregunta muy bien, así que espero que obtengas algunos buenos comentarios aquí. –

+2

Afortunadamente este es un proyecto de mascotas, así que tengo el lujo de explorar diferentes diseños. Mi tienda no ha adoptado WPF o MVVM porque los gastos generales y la incomodidad en esta etapa temprana no son aceptables para nuestros horarios actuales. Creo firmemente que esta es una tecnología que pagará grandes dividendos en productividad una vez que comprendamos cómo usarla, pero es un cambio de perspectiva que es difícil saber dónde trazar las líneas en un diseño. –

Respuesta

3

Una opción que funciona bien para la interacción entre viewmodels es enlazar directamente a las clases observer que se encuentran entre las clases de viewmodel.

+0

Gracias por el enlace; De hecho, estaba usando un patrón similar a este para otra coordinación, al compartir un servicio IMainViewModel, que es implementado por mi MainViewModel. Estoy pensando que puede tener sentido refactorizarlo más para que la funcionalidad 'compartida' no esté atada en el modelo para la ventana principal y, en cambio, sea un MainObserver. –

+1

Este ha sido un enfoque útil. Mi diseño sigue siendo un poco esquizofrénico, pero estoy empezando a ver cómo las VM pueden comunicarse mediante el uso de servicios compartidos. Se siente un poco invertido, ya que estoy acostumbrado a que un 'padre' sepa todo sobre sus 'hijos'. Ahora es más una cuestión de mi clase que dice "Necesito hacer esto" y una parte de la aplicación que no sé casi nada sobre cómo intensificar y cuidar de mí. –

3

Creo que desea que su nivel superior ViewModel tenga en cuenta la existencia del NestedViewModel, tiene sentido desde un punto de vista jerárquico, la vista maestra contiene la vista secundaria.

En mi opinión, su instinto es correcto, no se considera correcto que el ViewModel anidado exponga los comportamientos que se inician por las acciones del usuario en el nivel superior. En su lugar, el nivel superior ViewModel debería proporcionar comportamientos para la vista a la que está asociado.

Pero consideraría mover la responsabilidad de la construcción de la conexión a ICommand, y exponer este comando a través de su nivel superior ViewModel. El botón Aceptar en su cuadro de diálogo maestro se uniría a este comando, y el comando simplemente delegaría en el nivel superior ViewModel, por ejemplo, llamar al ViewModel.CreateConnection() cuando se ejecuta.

La responsabilidad de su control anidado es simplemente recopilar y exponer los datos a su NestedViewModel, para el consumo por el contenido ViewModel, y es teóricamente más reutilizable en diferentes contextos que requieren la misma información para ser ingresado (si cualquiera) - digamos que quería volver a usarlo para editar las conexiones ya creadas.

La única arruga sería si los diferentes tipos de NestedViewModel exponen un conjunto de datos radicalmente diferente.

Por ejemplo, se expone NombreHost y Puerto como propiedades, y otro expone Nombre de usuario Contraseña y .

En cuyo caso es posible que necesite hacer algún trabajo de infraestructura para que su nivel superior ViewModel.CreateConnection() aún funcione de manera limpia. Aunque si tiene una pequeña cantidad de tipos de control anidados, puede que no valga la pena, y un simple NestedViewModel verificación de tipo y yeso puede ser suficiente.

¿Esto le parece viable?

+0

El desafío aquí es que el ViewModel externo en realidad no conoce el tipo de su InnerViewModel en tiempo de compilación. Los controladores se incorporan como extensiones a la aplicación en tiempo de ejecución, con algún tipo de descubrimiento bajo el capó para conectar el control anidado específico a través de un DataTemplateSelector personalizado. Sé que el DataContext será implícitamente el ViewModel anidado específico, pero me parece hackeo inspeccionar el DataContext e intentar convertirlo en una interfaz compartida. –

0

Recientemente experimenté con Unity (biblioteca de Microsoft Enterprise) para usar la inyección de dependencia. Esa podría ser una ruta a seguir cuando se usan interfaces que definen completamente lo que ambos modelos de vista necesitan para no el uno del otro. MEF sería otra opción para la inyección de dependencia de la que soy consciente.

HTH

+0

Gracias, en realidad estoy usando MEF en esta aplicación y me ha ayudado bastante al permitir una extensibilidad muy rica de la IU. Es esta extensibilidad lo que crea desafíos de diseño, ya que ahora la IU aloja controles de los que realmente no sabe casi nada.De hecho, he encontrado una forma más limpia de hacerlo, que detallaré más una vez que llegue a casa hoy. –

Cuestiones relacionadas