Implementación del patrón MVVM con Prism

El patrón Model-View-ViewModel (MVVM) ayuda a separar de forma limpia la lógica de presentación y de negocios de la aplicación desde su interfaz de usuario (UI). Mantener una separación limpia entre la lógica de la aplicación y la interfaz de usuario ayuda a abordar numerosos problemas de desarrollo y diseño y puede hacer su aplicación mucho más fácil de probar, mantener y evolucionar. También puede mejorar enormemente las oportunidades de reutilización de código y permite a los desarrolladores y diseñadores de interfaces de usuario colaborar más fácilmente al desarrollar sus respectivas partes de la aplicación.

Utilizando el patrón MVVM, la interfaz de usuario de la aplicación y la presentación subyacente y la lógica empresarial se dividen en tres clases independientes: la vista, que encapsula la interfaz de usuario y la lógica de la interfaz de usuario; El modelo de vista, que encapsula la lógica y el estado de la presentación; Y el modelo, que encapsula la lógica empresarial y los datos de la aplicación.

Prism incluye ejemplos e implementaciones de referencia que muestran cómo implementar el patrón MVVM en una aplicación Xamarin Form. La Biblioteca Prism también proporciona características que pueden ayudarle a implementar el patrón en sus propias aplicaciones. Estas características incorporan las prácticas más comunes para implementar el patrón MVVM y están diseñadas para soportar la testeabilidad y para trabajar bien con Visual Studio.

Este Post proporciona una visión general del patrón MVVM y describe cómo implementar sus características fundamentales.

Responsabilidades y características de la clase

El patrón MVVM es una variante estrecha del patrón del modelo de presentación, optimizado para aprovechar algunas de las capacidades principales de Xamarin Form, como el enlace de datos, las plantillas de datos, los comandos y los comportamientos.

En el patrón MVVM, la vista encapsula la interfaz de usuario y cualquier lógica de interfaz de usuario, el modelo de vista encapsula la lógica y el estado de la presentación y el modelo encapsula la lógica empresarial y los datos. La vista interactúa con el modelo de vista a través de enlace de datos, comandos y eventos de notificación de cambios. El modelo de vista consulta, observa y coordina actualizaciones del modelo, convirtiendo, validando y agregando datos según sea necesario para mostrarlos en la vista.

La siguiente ilustración muestra las tres clases MVVM y su interacción.

Las clases MVVM y sus interacciones

Las clases MVVM y sus interacciones

Al igual que con todos los patrones de presentación separados, la clave para usar el patrón MVVM reside efectivamente en comprender la forma adecuada de factorizar el código de su aplicación en las clases correctas y en comprender las formas en que estas clases interactúan en varios escenarios. Las siguientes secciones describen las responsabilidades y características de cada una de las clases en el patrón MVVM.

La clase View

La responsabilidad de la vista es definir la estructura y la apariencia de lo que el usuario ve en la pantalla. Idealmente, el code-behind de una vista contiene sólo un constructor que llama al método InitializeComponent . En algunos casos, el code-behind puede contener código de lógica de interfaz de usuario que implementa comportamiento visual que es difícil o ineficiente para expresar en XAML (Extensible Application Markup Language), como animaciones complejas o cuando el código necesita manipular directamente elementos visuales que son Parte de la vista. No debe poner ningún código lógico en la vista que necesita para la prueba de unidad. Normalmente, el código lógico en el código de la vista posterior será probado a través de un enfoque de prueba de automatización de la interfaz de usuario.

En Xamarin Form, las expresiones de enlace de datos en la vista se evalúan en función de su contexto de datos. En MVVM, el contexto de datos de la vista se establece en el modelo de vista. El modelo de vista implementa propiedades y comandos a los que la vista puede enlazar y notifica la vista de cualquier cambio en el estado a través de eventos de notificación de cambios. Normalmente existe una relación uno a uno entre una vista y su modelo de vista.

Normalmente, las vistas son clases control- derivadas o UserControl- derivadas. Sin embargo, en algunos casos, la vista puede estar representada por una plantilla de datos, que especifica los elementos de la interfaz de usuario que se utilizarán para representar visualmente un objeto cuando se muestre. Mediante el uso de plantillas de datos, un diseñador visual puede definir fácilmente cómo se renderizará un modelo de vista o modificar su representación visual predeterminada sin cambiar el objeto subyacente ni el comportamiento del control que se utiliza para mostrarlo.

Las plantillas de datos pueden considerarse como vistas que no tienen ningún código por detrás. Están diseñados para enlazar a un tipo de modelo de vista específico cada vez que se requiere que se muestre en la interfaz de usuario. En tiempo de ejecución, la vista, tal como se define en la plantilla de datos, se instanciará automáticamente y su contexto de datos se establecerá en el modelo de vista correspondiente.

En Xamarin Form, puede asociar una plantilla de datos con un tipo de modelo de vista en el nivel de aplicación. Xamarin Form aplicará automáticamente la plantilla de datos a cualquier objeto de modelo de vista del tipo especificado cada vez que se muestren en la interfaz de usuario. Esto se conoce como plantilla de datos implícita. La plantilla de datos se puede definir en línea con el control que la utiliza o en un diccionario de recursos fuera de la vista principal y se agrupa declarativamente en el diccionario de recursos de la vista.

En resumen, la vista tiene las siguientes características clave:

  • 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 visual y estilo.
  • La vista hace referencia al modelo de vista a través de su propiedad DataContext . Los controles de la vista están 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 utilizar convertidores de valores para formatear los datos que se mostrarán en la interfaz de usuario o puede utilizar reglas de validación para proporcionar validación adicional de datos de entrada al usuario.
  • La vista define y maneja el comportamiento visual de la interfaz de usuario, como animaciones o transiciones que pueden ser activadas a partir de un cambio de estado en el modelo de vista o mediante la interacción del usuario con la interfaz de usuario.
  • La clave 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 interfaz de usuario específicos definidos en la vista.

La clase de modelo de vista

El modelo de vista en el patrón MVVM encapsula la lógica de presentación y los datos de la vista. No tiene referencia directa a la vista o ningún conocimiento sobre la implementación o el tipo específico de la vista. El modelo de vista implementa propiedades y comandos a los que la vista puede enlazar datos y notifica la vista de cualquier cambio de estado a través de eventos de notificación de cambios. Las propiedades y comandos que proporciona el modelo de vista definen la funcionalidad que ofrece la interfaz de usuario, pero la vista determina cómo se va a procesar dicha funcionalidad.

El modelo de vista es responsable de coordinar la interacción de la vista con cualquier clase de modelo que se requiera. Normalmente, existe una relación de uno a muchos entre el modelo de vista y las clases de modelo. El modelo de vista puede optar por exponer clases de modelo directamente a la vista para que los controles en la vista puedan enlazar datos directamente a ellos. En este caso, las clases de modelo deberán diseñarse para soportar la vinculación de datos y los eventos de notificación de cambios relevantes.

El modelo de vista puede convertir o manipular datos de modelo para que pueda ser consumido fácilmente por la vista. El modelo de vista puede definir propiedades adicionales para soportar específicamente la vista; Estas propiedades normalmente no forman parte del modelo (o no pueden añadirse). Por ejemplo, el modelo de vista puede combinar el valor de dos campos para facilitar la presentación de la vista, o puede calcular el número de caracteres restantes para la entrada de campos con una longitud máxima. El modelo de vista también puede implementar lógica de validación de datos para garantizar la coherencia de los datos.

El modelo de vista también puede definir estados lógicos que la vista puede utilizar para proporcionar cambios visuales en la interfaz de usuario. La vista puede definir cambios de diseño o estilo que reflejen el estado del modelo de vista. Por ejemplo, el modelo de vista puede definir un estado que indica que los datos se envían de forma asíncrona a un servicio web. La vista puede mostrar una animación durante este estado para proporcionar retroalimentación visual al usuario.

Normalmente, el modelo de vista definirá comandos o acciones que se pueden representar en la interfaz de usuario y que el usuario puede invocar. Un ejemplo común es cuando el modelo de vista proporciona un comando Enviar que permite al usuario enviar datos a un servicio web oa un repositorio de datos. La vista puede elegir representar ese comando con un botón para que el usuario pueda hacer clic en el botón para enviar los datos. Normalmente, cuando el comando no está disponible, su representación de interfaz de usuario asociada se deshabilita. Los comandos proporcionan una forma de encapsular las acciones del usuario y separarlas de forma clara de su representación visual en la interfaz de usuario.

En resumen, el modelo de vista tiene las siguientes características clave:

  • El modelo de vista es una clase no visual y no se deriva de ninguna clase base de Xamarin Form. Encapsula la lógica de presentación requerida para soportar un caso de uso o tarea de usuario en la aplicación. El modelo de vista es comprobable independientemente de la vista y el modelo.
  • Normalmente, el modelo de vista 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 cambios a través de las interfaces INotifyPropertyChanged e INotifyCollectionChanged .
  • El modelo de vista coordina la interacción de la vista con el modelo. Puede convertir o manipular datos para que pueda ser consumido fácilmente por la vista y puede implementar propiedades adicionales que pueden no estar presentes en el modelo. También puede implementar validación de datos a través de las interfaces IDataErrorInfo o INotifyDataErrorInfo .
  • El modelo de vista puede definir estados lógicos que la vista puede representar visualmente al usuario.
Gg405484.note (es-es, PandP.40) .gifNota:
Muchas veces, determinar dónde debe implementarse determinada funcionalidad no es obvia. La regla general es: Cualquier cosa relacionada con el aspecto visual específico de la interfaz de usuario en la pantalla y que podría volver a denominarse más tarde (incluso si actualmente no está planeando volver a diseñarlo) debe entrar en la vista; Cualquier cosa que sea importante para el comportamiento lógico de la aplicación debe entrar en el modelo de vista. Además, debido a que el modelo de vista no debe tener conocimiento explícito de los elementos visuales específicos de la vista, el código para manipular de forma programática elementos visuales dentro de la vista debe residir en el código de la vista o estar encapsulado en un comportamiento. Del mismo modo, el código para recuperar o manipular elementos de datos que se van a mostrar en la vista a través del enlace de datos debe residir en el modelo de vista.

La Clase Modelo

El modelo en el patrón MVVM encapsula la lógica empresarial y los datos. La lógica de negocio se define como cualquier lógica de aplicación que se ocupe de la recuperación y gestión de datos de aplicación y para asegurarse de que se imponen las reglas de negocio que garantizan la coherencia y la validez de los datos. Para maximizar las oportunidades de reutilización, los modelos no deben contener ningún comportamiento de uso específico de caso o de usuario específico de la tarea o la lógica de la aplicación.

Normalmente, el modelo representa el modelo de dominio del cliente para la aplicación. Puede definir estructuras de datos basadas en el modelo de datos de la aplicación y en cualquier lógica de validación y de negocio. El modelo también puede incluir el código para admitir el acceso a los datos y el almacenamiento en caché, aunque normalmente se emplea un repositorio o servicio de datos por separado. A menudo, el modelo y la capa de acceso a datos se generan como parte de una estrategia de acceso a datos o de servicio.

Normalmente, el modelo implementa las facilidades que hacen que sea fácil de enlazar a la vista. Esto generalmente significa que admite la notificación de propiedad y colección modificada a través de las interfaces INotifyPropertyChanged e INotifyCollectionChanged . Las clases de modelos que representan colecciones de objetos normalmente derivan de la clase ObservableCollection <T> , que proporciona una implementación de la interfaz INotifyCollectionChanged .

El modelo también puede admitir validación de datos y notificación de errores a través de las interfaces IDataErrorInfo (o INotifyDataErrorInfo ). Las interfaces IDataErrorInfo e INotifyDataErrorInfo permiten que el enlace de datos de Xamarin Form sea notificado cuando los valores cambian para que la interfaz de usuario pueda actualizarse. También permiten el soporte para la validación de datos y la generación de informes de errores en la capa de IU.

Gg405484.note (es-es, PandP.40) .gifNota:
¿Qué pasa si sus clases de modelo no implementan las interfaces requeridas? 
A veces necesitará trabajar con objetos de modelo que no implementen las interfaces INotifyPropertyChanged , INotifyCollectionChanged , IDataErrorInfo o INotifyDataErrorInfo . En esos casos, es posible que el modelo de vista necesite ajustar los objetos del modelo y exponer las propiedades necesarias a la vista. Los valores de estas propiedades serán proporcionados directamente por los objetos del modelo. El modelo de vista implementará las interfaces necesarias para las propiedades que expone para que la vista pueda enlazar datos fácilmente a ellas.

El modelo tiene las siguientes características clave:

  • Las clases de modelo son clases no visuales que encapsulan los datos y la lógica empresarial de la aplicación. Son responsables de gestionar los datos de la aplicación y de garantizar su coherencia y validez encapsulando las reglas empresariales y la lógica de validación de datos requeridas.
  • Las clases de modelo no hacen referencia directa a las clases de modelo de vista o vista y no tienen dependencia de cómo se implementan.
  • Las clases de modelo normalmente proporcionan eventos de notificación de cambio de propiedad y de colección a través de las interfaces INotifyPropertyChanged e INotifyCollectionChanged . Esto les permite ser fácilmente vinculados a los datos en la vista. Las clases de modelo que representan colecciones de objetos normalmente derivan de la clase ObservableCollection <T> .
  • Normalmente, las clases de modelo proporcionan validación de datos y notificación de errores a través de las interfaces IDataErrorInfo o INotifyDataErrorInfo .
  • Las clases de modelo suelen utilizarse conjuntamente con un servicio o repositorio que encapsula el acceso a los datos y el almacenamiento en caché.

Interacciones de clase

El patrón MVVM proporciona una separación clase entre la interfaz de usuario de su aplicación, su lógica de presentación y su lógica de negocio y datos, separándolos en clases separadas. Por lo tanto, al implementar MVVM, es importante que el código de la aplicación se aplique a las clases correctas, tal como se describe en la sección anterior.

La vista bien diseñada, el modelo de vista y las clases de modelo no sólo encapsularán el tipo correcto de código y comportamiento; También se diseñarán de modo que puedan interactuar fácilmente entre sí a través de enlaces de datos, comandos y interfaces de validación de datos.

Las interacciones entre la vista y su modelo de vista son quizás las más importantes a considerar, pero las interacciones entre las clases de modelo y el modelo de vista también son importantes. En las siguientes secciones se describen los distintos patrones de estas interacciones y se describe cómo diseñarlas cuando implementen el patrón MVVM en sus aplicaciones.

El enlace de datos

El enlace de datos desempeña un papel muy importante en el patrón MVVM. Xamarin Form proporciona poderosas capacidades de enlace de datos. Su modelo de vista y (idealmente) sus clases de modelo se deben diseñar para apoyar la vinculación de datos para que puedan aprovechar estas capacidades. Normalmente, esto significa que deben implementar las interfaces correctas.

El enlace de datos de Xamarin Form admite varios modos de vinculación de datos. Con vinculación de datos unidireccional, los controles de interfaz de usuario pueden enlazarse a un modelo de vista para que reflejen el valor de los datos subyacentes cuando se muestre la presentación. El enlace de datos bidireccional también actualizará automáticamente los datos subyacentes cuando el usuario lo modifique en la interfaz de usuario.

Para garantizar que la interfaz de usuario se mantiene actualizada cuando los datos cambian en el modelo de vista, debe implementar la interfaz de notificación de cambios adecuada. Si define propiedades que pueden ser datos enlazados, debe implementar la interfaz INotifyPropertyChanged . Si el modelo de vista representa una colección, debe implementar la interfaz INotifyCollectionChanged o derivar de la clase ObservableCollection <T> que proporciona una implementación de esta interfaz. Ambas interfaces definen un evento que se genera cada vez que se cambian los datos subyacentes. Todos los controles vinculados a datos se actualizarán automáticamente cuando se generen estos eventos.

En muchos casos, un modelo de vista definirá las propiedades que devuelven objetos (y que, a su vez, pueden definir propiedades que devuelven objetos adicionales). El enlace de datos de Xamarin Form

admite el enlace a propiedades anidadas a través de la propiedad Path . Por lo tanto, es muy común que el modelo de vista de una vista devuelva referencias a otras clases de modelo o modelo de vista. Todas las clases de modelo y modelo de vista accesibles a la vista deben implementar las interfaces INotifyPropertyChanged o INotifyCollectionChanged , según corresponda.

En las siguientes secciones se describe cómo implementar las interfaces necesarias para soportar la vinculación de datos dentro del patrón MVVM.

Implementación de INotifyPropertyChanged

La implementación de la interfaz INotifyPropertyChanged en su modelo de vista o clases de modelo les permite proporcionar notificaciones de cambios a cualquier control enlazado a datos en la vista cuando cambia el valor de la propiedad subyacente. La implementación de esta interfaz es sencilla, como se muestra en el siguiente ejemplo de código.

public class MyViewModel : BindableBase
{
    public ICollectionView Customers { get; private set; }

    public MyViewModel( ObservableCollection<Customer> customers )
    {
        // Initialize the CollectionView for the underlying model
        // and track the current selection.
        Customers = new ListCollectionView( customers );
        
        Customers.CurrentChanged +=SelectedItemChanged;
    }

    private void SelectedItemChanged( object sender, EventArgs e )
    {
        Customer current = Customers.CurrentItem as Customer;
        ...
    }
    ...
}


 

Autor: jaimeh1982

Analista de sistemas actualmente trabajando en entorno de desarrollo web

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *