Conceptos básicos de MVVM: ¿qué debe hacer un ViewModel?

83

Tratando de comprender los conceptos de MVVM, ya leí varios blogs y miré algunos proyectos.

Por lo que entiendo, una Vista es tonta, solo sabe cómo presentar algo que se le pasa.

Los modelos son solo datos simples, y un ViewModel es algo que actúa como un relleno entre los dos, que debe obtener información del Modelo y pasarla a la Vista , y la Vista debe saber cómo presentarla. O al revés, si la información en la Vista cambia, debería pasar el cambio al Modelo .

Pero todavía no tengo idea de cómo aplicar el concepto. ¿Alguien puede explicar un escenario muy simple para que pueda captar el concepto? Ya he visto varios proyectos, pero todavía no tiene mucho sentido, así que si alguien pudiera escribirlo en un inglés sencillo, estaría bien.

RKM
fuente
2
No puedo estar de acuerdo con la afirmación de que la vista "solo sabe cómo presentar algo que se le pasa". Ver toma datos de VM. Nadie le pasa datos. Nadie sabe de vista. Ésta es una diferencia importante con MVP. En MVP (puede pensar en ello como una aplicación WPF simple con lógica de código subyacente, es un patrón MVP) el código subyacente es un presentador que pasa datos a Ver como usted dijo.
Grigory

Respuestas:

146

Me gusta pensarlo de esta manera:

Las vistas, como dices, son tontas. Josh Smith, escritor del artículo fundamental y frecuentemente vinculado de MSDN sobre MVVM, ha dicho que las vistas son "la ropa que usan los datos". Las vistas nunca contienen datos ni los manipulan directamente, solo están vinculados a propiedades y comandos de sus modelos de vista.

Los modelos son objetos que modelan el dominio de su aplicación , como en los objetos comerciales. ¿Tu aplicación es una tienda de música? Quizás sus objetos modelo sean artistas, álbumes y canciones. ¿Es su aplicación un navegador de organigramas? Quizás los objetos de su modelo sean gerentes y empleados. Estos objetos de modelo no están relacionados con ningún tipo de representación visual, y ni siquiera están directamente relacionados con la aplicación en la que los está colocando; sus objetos de modelo deben tener sentido por sí mismos como una familia de objetos que representan algún tipo de dominio. La capa de modelo también suele incluir cosas como accesos de servicio.

Esto nos lleva a Viewmodels. ¿Qué son? Son objetos que modelan una aplicación GUI, lo que significa que proporcionan datos y funciones para que las utilicen las vistas. Son los que definen la estructura y el comportamiento de la aplicación real que está creando. Para los objetos del modelo, el dominio es cualquier dominio que elija (tienda de música, navegador de organigramas, etc.), pero para el modelo de vista, el dominio es una aplicación gráfica. Sus modelos de vista encapsularán el comportamiento y los datos de todo lo que hace su aplicación. Van a exponer objetos y listas como propiedades, así como cosas como Comandos. Un comando es solo un comportamiento (en su forma más simple, una llamada a un método) envuelto en un objeto que lo transporta; esta idea es importante porque las vistas son impulsadas por el enlace de datos, que adjunta controles visuales a los objetos. En MVVM, no le das a un botón un método de controlador de clic,

Para mí, los bits más confusos fueron los siguientes:

  • Aunque los modelos de vista son modelos de una aplicación gráfica, no hacen referencia directa ni utilizan conceptos visuales. Por ejemplo, no desea referencias a los controles de Windows en sus ViewModels; esas cosas van en la vista. ViewModels simplemente expone datos y comportamientos a controles u otros objetos que se unirán a ellos. Por ejemplo, ¿tiene una vista con un ListBox en ella? Es casi seguro que su modelo de vista tendrá algún tipo de colección. ¿Tu vista tiene botones? Es casi seguro que su modelo de vista tendrá algunos comandos.
  • Hay algunos tipos de objetos que podrían considerarse "modelos de vista". El tipo de modelo de vista más simple de entender es el que representa directamente un control o una pantalla en una relación 1: 1, como en "la pantalla XYZ tiene un cuadro de texto, un cuadro de lista y tres botones, por lo que el modelo de vista necesita una cadena, una colección, y tres mandamientos ". Otro tipo de objeto que encaja en la capa de modelo de vista es un envoltorio alrededor de un objeto de modelo que le da comportamiento y lo hace más utilizable por una vista; aquí es donde entra en los conceptos de capas de modelo de vista "gruesas" y "finas". Una capa de modelo de vista "delgada" es un conjunto de modelos de vista que exponen los objetos de su modelo directamente a las vistas, lo que significa que las vistas terminan vinculando directamente a las propiedades de los objetos del modelo. Esto puede funcionar para cosas como vistas simples de solo lectura, pero ¿y si desea tener un comportamiento asociado con cada objeto? No quiere eso en el modelo, porque el modelo no está relacionado con la aplicación, solo está relacionado con su dominio. Puede ponerlo en un objeto que envuelva su objeto modelo y ofrezca datos y comportamientos más fáciles de vincular. Este objeto contenedor también se considera un modelo de vista, y tenerlos da como resultado una capa de modelo de vista "más gruesa", donde sus vistas nunca terminan vinculando directamente a nada en una clase de modelo. Las colecciones contendrán modelos de vista que envuelvan modelos en lugar de contener modelos en sí mismos. Puede ponerlo en un objeto que envuelva su objeto modelo y ofrezca datos y comportamientos más fáciles de vincular. Este objeto contenedor también se considera un modelo de vista, y tenerlos da como resultado una capa de modelo de vista "más gruesa", donde sus vistas nunca terminan vinculando directamente a nada en una clase de modelo. Las colecciones contendrán modelos de vista que envuelvan modelos en lugar de contener modelos en sí mismos. Puede ponerlo en un objeto que envuelva su objeto modelo y ofrezca datos y comportamientos más fáciles de vincular. Este objeto contenedor también se considera un modelo de vista, y tenerlos da como resultado una capa de modelo de vista "más gruesa", donde sus vistas nunca terminan vinculando directamente a nada en una clase de modelo. Las colecciones contendrán modelos de vista que envuelvan modelos en lugar de contener modelos en sí mismos.

El agujero del conejo es más profundo: hay muchos modismos para descubrir, como ValueConverters, que mantienen MVVM en funcionamiento, y hay mucho que aplicar cuando comienza a pensar en cosas como Blendability, pruebas y cómo pasar datos en su aplicación y asegurarse de que cada modelo de vista tiene acceso al comportamiento que necesita (aquí es donde entra la inyección de dependencia), pero es de esperar que lo anterior sea un buen comienzo. La clave es pensar en sus imágenes, su dominio y la estructura y el comportamiento de su aplicación real como tres cosas diferentes.

nlawalker
fuente
3
+1 - Terminé aquí porque estaba confundido por un ViewModel "contenedor" encontrado en algún código de muestra. Gracias por
aclararme
1
Gran respuesta: desearía poder +10.
Nick Hodges
1
@nlawalker ¡Muy impresionante! Los puntos dobles que comentaste arriba me han confundido durante mucho tiempo. Muchos artículos y blogs solo cuentan las "características clave" de MVVM, pero cuando intentas conseguirlo, las cosas comienzan a ser muy complicadas. ! Tales como "¿Cómo navegar por esas vistas?" "¿Cuál es la granularidad adecuada cuando diseñamos ViewModels?" "¿Una vista debe tener un ViewModel coincidente o se puede reutilizar un ViewModel en diferentes vistas?" Su aclaración sobre el ViewModel compuesto con "Slim VM" y "Thick VM" realmente tiene sentido. Lo estoy intentando, funciona bien ¡lejos! :)
Garra
@nlawalker ¡Gracias! Y otra pregunta: tengo treeView y hago TreeViewViewModel. Entonces, si creo métodos como: ExpandTree () en mi ViewModel. ¿Es la forma correcta?
user2545071
Vaya, este es un artículo excelente, muy buen trabajo @nlawalker
Vivek Shukla
25

Utilizando este artículo increíblemente útil como fuente, aquí hay un resumen de View , ViewModel y Model .


Ver:

  • La vista es un elemento visual, como una ventana, una página, un control de usuario o una plantilla de datos. La vista define los controles contenidos en la vista y su diseño y estilo visual.

  • La vista hace referencia al modelo de vista a través de su DataContextpropiedad. Los controles de la vista son datos vinculados a las propiedades y comandos expuestos por el modelo de vista.

  • La vista puede personalizar el comportamiento de enlace de datos entre la vista y el modelo de vista. Por ejemplo, la vista puede usar convertidores de valor para formatear los datos que se mostrarán en la interfaz de usuario, o puede usar reglas de validación para proporcionar una validación de datos de entrada adicional al usuario.

  • La vista define y maneja el comportamiento visual de la interfaz de usuario, como animaciones o transiciones que pueden desencadenarse a partir de un cambio de estado en el modelo de vista o mediante la interacción del usuario con la interfaz de usuario.

  • El código subyacente de la vista puede definir la lógica de la interfaz de usuario para implementar un comportamiento visual que es difícil de expresar en XAML o que requiere referencias directas a los controles de la interfaz de usuario específicos definidos en la vista.

NOTA:
Debido a que el modelo de vista no debe tener un conocimiento explícito de los elementos visuales específicos en la vista, el código para manipular mediante programación los elementos visuales dentro de la vista debe residir en el código subyacente de la vista o estar encapsulado en un comportamiento.


Ver modelo:

  • El modelo de vista es una clase no visual y no se deriva de ninguna clase base de WPF o Silverlight. Encapsula la lógica de presentación necesaria para admitir un caso de uso o una tarea de usuario en la aplicación. El modelo de vista se puede probar independientemente de la vista y el modelo.

  • El modelo de vista normalmente no hace referencia directa a la vista. Implementa propiedades y comandos a los que la vista puede enlazar datos. Notifica la vista de cualquier cambio de estado a través de eventos de notificación de cambio a través de las interfaces INotifyPropertyChangedy INotifyCollectionChanged.

  • El modelo de vista coordina la interacción de la vista con el modelo. Puede convertir o manipular datos para que la vista pueda consumirlos fácilmente y puede implementar propiedades adicionales que pueden no estar presentes en el modelo. También puede implementar la validación de datos a través de las interfaces IDataErrorInfoo INotifyDataErrorInfo.

  • El modelo de vista puede definir estados lógicos que la vista puede representar visualmente para el usuario.

NOTA:
Todo lo que sea importante para el comportamiento lógico de la aplicación debe incluirse en el modelo de vista. El código para recuperar o manipular elementos de datos que se mostrarán en la vista a través del enlace de datos debe residir en el modelo de vista.


Modelo:

  • Las clases de modelo son clases no visuales que encapsulan los datos y la lógica empresarial de la aplicación. Son responsables de administrar los datos de la aplicación y de garantizar su consistencia y validez al encapsular las reglas comerciales requeridas y la lógica de validación de datos.

  • Las clases de modelo no hacen referencia directa a la vista o las clases de modelo de vista y no dependen de cómo se implementan.

  • Las clases de modelo suelen proporcionar eventos de notificación de cambios de propiedades y colecciones a través de las interfaces INotifyPropertyChangedy INotifyCollectionChanged. Esto les permite enlazar datos fácilmente en la vista. Las clases de modelo que representan colecciones de objetos normalmente derivan de la ObservableCollection<T>clase.

  • Las clases de modelo suelen proporcionar validación de datos e informes de errores a través de las interfaces IDataErrorInfoo INotifyDataErrorInfo.

  • Las clases de modelo se utilizan normalmente junto con un servicio o repositorio que encapsula el acceso a los datos y el almacenamiento en caché.

Dom
fuente
17

He escrito esto en un "inglés simple" como se me ocurre en esta serie de MVVM . En particular, este diagrama es probablemente la explicación breve más simple.

Dicho esto, básicamente, el "modelo" son sus datos o reglas comerciales. Realmente no debería saber cómo o dónde se usará, y especialmente no qué tecnología lo usará. El "modelo" es el núcleo central de la aplicación, y no debería tener que preocuparse por si la aplicación es WPF, Silverlight, Windows Forms, ASP.NET, etc. Es simplemente "ella misma" en su forma pura.

La "Vista" es la parte que es completamente específica de la tecnología. En MVVM, idealmente, la vista debería ser casi 100% XAML, ya que esto proporciona grandes ganancias de flexibilidad.

Sin embargo, es necesario que haya algo que traduzca la información del modelo en alguna forma en la que sea utilizable por la tecnología en cuestión; aquí es donde entra en juego ViewModel. Por ejemplo, esto a menudo "envuelve" las clases del modelo en un "ViewModel" para esos datos específicos que incluyen comandos (para ejecutar la lógica), implementos INotifyPropertyChanged(para el soporte de enlace de datos), etc. Eso es todo, es el puente que hace que el modelo utilizable por la Vista.

Reed Copsey
fuente
OK gracias. Pensé en el Modelo como objetos y en ViewModel como métodos para manejar los objetos, de modo que una vista pueda entender los "objetos" del Modelo. Pero me dijeron que esto está mal, que ViewModel en sí mismo también son objetos. Supongo que esto es lo que realmente me confunde.
RKM
@Rosie: Recomendaría leer (o al menos hojear) mi serie que cité. Lo escribí específicamente porque hay pocos (casi ningún) artículos sobre MVVM que no asuman que usted entiende MVC o MVP, etc. Es realmente una transición "paso a paso";)
Reed Copsey
Darse cuenta de esto es un poco de zombie-threading ... Su diagrama dice que la VM contiene "Estado y lógica específicos de la aplicación " (mi énfasis). ¿Eso sugiere que cree que la máquina virtual podría / debería contener lógica de control de calidad de datos? El RssWpfMVVM.csproj relacionado no parece tener ningún control de calidad obvio en sus dos modelos de vista.
ruffin
1

Puede encontrar una gran introducción a MVVM en el video de Jason Dolinger aquí . Guardé el video conmigo durante bastante tiempo cuando comencé, es realmente útil.

Filipe Miguel
fuente
1
El enlace está muerto
ibrahim mahrir
1
@ibrahimmahrir ~ He actualizado el enlace a una URL funcional. Estoy descargando el video ahora.
InteXX
0

Crear un modelo de vista que presente una fachada coherente sobre el modelo subyacente puede ser mucho más complejo de lo que parece. Este artículo sobre la creación de objetos ViewModel demuestra cómo crear un ViewModel e ilustra algunos de los problemas que probablemente encontrará, junto con lo que parecen soluciones razonables. Cuando lo leí, faltaba la sección sobre el manejo de colecciones, pero aún tiene algunos puntos interesantes.

Sprotty
fuente