2009-11-25 8 views
14

Tengo un control de usuario que contiene otros controles de usuario. Estoy usando MVVM. Cada control de usuario tiene una VM correspondiente. ¿Cómo se envían estos controles de usuario entre ellos? Quiero evitar escribir cualquier código en el código xaml detrás. Particularmente, estoy interesado en cómo los controles (dentro del control principal del usuario) se comunicarán entre sí y cómo hablarán con el control del usuario del contenedor.MVVM: ¿cuál es la forma ideal para que los controles de usuario se comuniquen entre sí?

EDIT: Sé que el uso de eventos-delegados me ayudará a resolver este problema. Pero, quiero evitar escribir cualquier código en xaml code-behind.

Respuesta

1

Creo que la mejor solución sería utilizar el patrón de editor/suscriptor. Cada control registra algunos eventos y adjunta delegados a eventos expuestos por otros controles.

Para exponer eventos y adjuntarlos, necesitaría utilizar algún tipo de servicio Mediator/EventBroker. Encontré un buen ejemplo here

+0

¿Puede explicar esto en detalle? ¿Quiere decir usar delegado y eventos de CLR? – Sandbox

+0

Acabo de editar mi respuesta agregando el enlace a la presentación con un código de ejemplo del blog de Marlon Grech. Los modelos de vista se comunican en el patrón del editor/suscriptor (no se necesita código). El servicio de mediación utiliza delegados CLR para registrar manejadores de eventos. – PanJanek

1

La mejor manera de hacer esto en mi opinión es a través de Commanding (Comandos enrutados/RelayCommand, etc.).

Quiero evitar escribir cualquier código en el código xaml detrás.

Si bien este es un objetivo loable, hay que aplicar un poco de sentido práctico a esto, no se debe aplicar el 100% como "No te" tipo de regla.

+0

http://codebetter.com/blogs/glenn.block/archive/2009/08/02/the-spirit-of-mvvm-viewmodel-it-s-not-a-code-counting-exercise.aspx –

+0

Genial publicar, tendré que leer esto! –

0

Puede comunicarse entre elementos en la UI utilizando el enlace de elemento, por lo que suponiendo que un control de usuario que creó expone una propiedad, los otros controles de usuario podrían vincularse a ella. Puede configurar el enlace, usar propiedades de dependencia en lugar de propiedades básicas/implementar INotifyPropertyChanged pero, en teoría, es posible, pero requiere cierta previsión para permitir la comunicación de esta manera.

Probablemente le resultará mucho más fácil usar una combinación de eventos, códigos y propiedades que probar de una manera puramente declarativa, pero en teoría es posible.

14

Normalmente, lo mejor es intentar reducir la cantidad de comunicación entre las partes, ya que cada vez que dos controles de usuario "hablan" entre sí, está introduciendo una dependencia entre ellos.

Dicho esto, hay un par de cosas a tener en cuenta:

  • UserControls siempre puede "hablar" con su control a través de la exposición que contiene propiedades y el uso de DataBinding. Esto es muy bueno, ya que conserva el estilo MVVM en todos los aspectos.
  • El control que contiene puede utilizar las propiedades de "enlace" dos propiedades en dos controles de usuario juntos, de nuevo, la preservación de los límites limpias

Si necesita tener una comunicación más explícita, hay dos principales approachs.

  1. implementar un servicio común a ambos elementos, y utilizar la inyección de dependencias para proporcionar la aplicación en tiempo de ejecución. Esto permite que los controles hablen con el servicio, lo que a su vez puede mantener sincronizados los controles, pero también mantiene la dependencia al mínimo.
  2. Usa algún tipo de mensaje para pasar mensajes entre controles.Muchos marcos MVVM tienen este enfoque, ya que desacopla el envío del mensaje de recibir el mensaje, nuevamente, manteniendo las dependencias al mínimo.
+3

Para el punto 2: MvvmFoundation de Josh Smith tiene una clase 'Messenger' que usa un mecanismo de Registrar/Notificar para pasar mensajes a través de las máquinas virtuales. Se almacenan como referencias débiles para evitar pérdidas de memoria y funcionan muy bien. – kiwipom

+1

Sí, también recomendaría la clase 'Messenger' en MVVM Foundation. Buena cosa. – Oskar

+1

Sí, eso es en lo que estaba pensando cuando mencioné "Mensajes para pasar mensajes". Es una técnica efectiva, si no quieres que DI inyecte servicios. –

0

Puede compartir algunos objetos de vista del modelo entre los controles, así como los comandos ...

Por ejemplo, puede tener cierto control principal, que contiene otros dos controles. Y tiene algunas funciones de filtrado en el control principal, pero desea permitir que el usuario configure alguna parte del filtro en el primer subcontrol (como "Filtro completo") y alguna parte del filtro en otro (como "Filtro rápido" "). También desea poder comenzar a filtrar desde cualquiera de los subcontroles. Posteriormente, se podría usar un código como éste:

public class MainControlViewModel : ObservableObject 
{ 
    public FirstControlViewModel firstControlViewModel; 
    public SecondControlViewModel firstControlViewModel; 

    public ICommand FilterCommand; 
    public FilterSettings FilterSettings; 

    public MainControlViewModel() 
    { 
     //... 

     this.firstControlViewModel = new FirstControlViewModel(this.FilterSettings, this.FilterCommand); 
     this.secondControlViewModel = new SecondControlViewModel(this.FilterSettings, this.FilterCommand); 
    } 
} 

public class FirstControlViewModel : ObservableObject 
{ 
    //... 
} 

public class SecondControlViewModel : ObservableObject 
{ 
    //... 
} 

En el XAML de control principal va a encuadernar sub-controls DataContext a los correspondientes Visualización de modelos. Siempre que un subcontrol cambie la configuración del filtro o ejecute un comando, se notificará a otro subcontrol.

3

Existen muchos mecanismos diferentes para esto, pero primero debe averiguar en qué capa de su arquitectura pertenece esta comunicación.

Uno de los propósitos del marco de MVVM es que se pueden realizar vistas diferentes sobre el mismo modelo de vista. ¿Hablarían esos controles de usuario solo en la vista que está implementando actualmente, o tendrían que hablar entre ellos en otras vistas posibles? En el último caso, desea implementarlo debajo del nivel de vista, ya sea en el modelo de vista o en el modelo mismo.

Un ejemplo del primer caso puede ser si su aplicación se ejecuta en una superficie de visualización muy pequeña. Tal vez sus controles de usuario tengan que competir por espacio visual. Si el usuario hace clic en un control de usuario para maximizar, los demás deben minimizar. Esto no tendría nada que ver con el modelo de vista, es solo una adaptación a la tecnología.

O tal vez tiene diferentes modelos de vista con diferentes controles de usuario, donde las cosas pueden suceder sin cambiar el modelo. Un ejemplo de esto podría ser la navegación. Tiene una lista de algo y un panel de detalles con campos y botones de comando que están conectados al elemento seleccionado en la lista. Es posible que desee probar la lógica de qué botones están habilitados para cada elemento. El modelo no se preocupa por el elemento que está mirando, solo cuando se presionan los comandos de los botones o cuando se cambian los campos.

La necesidad de esta comunicación puede estar incluso en el modelo en sí. Tal vez tiene datos desnormalizados que se actualizan porque se cambian otros datos. Entonces los diversos modelos de vista que están en acción deben cambiar debido a las ondas de cambios en el modelo.

Por lo tanto, para resumir: "Depende ...."

0

Como otros han dicho que tiene un par de opciones.

La exposición de DepedencyProperties en sus controles de usuario y la unión a aquellas propiedades proporciona una solución XAML pura en la mayoría de los casos, pero puede introducir algunas dependencias de interfaz de usuario a fin de que los enlaces para ver entre sí

La otra opción es un patrón de mensajería desacoplado para enviar mensajes entre ViewModels. Me gustaría que tus controles de usuario se vinculen a propiedades en tus propias máquinas virtuales y luego en el cambio de propiedad dentro de esa máquina virtual puede "publicar" un mensaje que notifica a otros "suscriptores" que algo ha sucedido y pueden reaccionar a ese mensaje como quieran .

que tienen una entrada de blog sobre este mismo tema si ayuda: http://www.bradcunningham.net/2009/11/decoupled-viewmodel-messaging-part-1.html

0

Si está usando MVVM estricta, entonces el control del usuario es una vista y sólo debe "hablar", o más bien, se unen , a su ViewModel. Dado que es muy probable que sus ViewModels ya implementen INotifyPropertyChanged, siempre que tengan una referencia entre ellos, pueden usar los eventos PropertyChanged para recibir notificaciones cuando cambien las propiedades, o pueden llamar a métodos (mejor si es a través de una interfaz) para comunicarse con cada uno otro.

+0

, ¿quiere decir que si dos controles de usuario tienen que hablar entre ellos, entonces deberían hacerlo a través de sus respectivas máquinas virtuales? y no creo que esté completamente de acuerdo con el hecho de que deberían suscribirse al evento PropertyChanged de los demás. – Sandbox

+0

@Sandbox: en el caso de que esté utilizando MVVM verdadero, la vista conoce su ViewModel, pero las vistas no deberían conocerse entre sí, por lo que no, no deberían hablar directamente entre sí. Sería difícil presionar para probar la comunicación entre vistas si lo hiciera de esa manera.Y puede usar el método que desee para que ViewModels se conozca o se comunique entre sí. .NET está lleno de opciones. Use lo que sea que se ajuste a la necesidad. –

7

Su problema conceptual está aquí:

de control Cada usuario tiene una máquina virtual correspondiente.

Tener un ViewModel separado para cada vista prácticamente anula el concepto de un ViewModel. ViewModels no debe ser uno a uno con las vistas, de lo contrario no son más que código glorificado detrás.

Un modelo de vista capta el concepto de "estado de la interfaz de usuario actual" - como lo que la página que se encuentra y si está o no se está editando -. En contraposición a los "valores de datos actuales

Realmente para cosechar los beneficios de MV-VM determinan la cantidad de clases de ViewModel utilizadas en función de los distintos elementos que necesitan estado. Por ejemplo, si tiene una lista de elementos, cada uno de los cuales puede mostrarse en 3 estados, necesita una VM por artículo. , si tiene tres vistas, todas las cuales muestran datos de 3 maneras diferentes, dependiendo de una configuración común, la configuración común debe capturarse en una sola VM.

Una vez que haya estructurado sus ViewModels para reflejar el requisitos de la tarea en cuestión generalmente se encuentra que no hay necesidad ni deseo de comunicar el estado entre vistas. Si existe tal necesidad, lo mejor que puede hacer es volver a evaluar su diseño de ViewModel para ver si un ViewModel compartido podría beneficiarse de una pequeña cantidad de información de estado adicional.

Habrá momentos en que la complejidad de la aplicación dicte el uso de varios ViewModels para el mismo objeto de modelo. En este caso, los ViewModels pueden mantener referencias a un objeto de estado común.

Cuestiones relacionadas