MVVMBasicDemo1: Patrón de diseño MVVM con aplicaciones basadas en WPF Resultado de imagen de WPF (Windows Presentation Foundation)

WPF (Windows Presentation Foundation) es una tecnología de MS para diseñar interfaces de usuario tomando ideas de técnicas Web y aplicaciones Windows. WPF permite definir las ventanas en ficheros de texto plano que contienen un lenguaje de etiquetado llamado XAML (basado en XML).

El proyecto completo se puede descargar en GitHub: https://github.com/ikerlandajuela/MVVMBasicDemo1.

 

De está forma separa las capas con la lógica de la aplicación y la capa de presentación donde interactuamos con el usuario. Está separación tan nítida propicia adoptar patrones de diseño como MVVM (Model-View-ViewModel ) para desarrollar aplicaciones complejas.

WPF emplea data-binding para conectar  la UI (User Interface) con la lógica de la aplicación, gracias a ello cuando un origen de dato cambia su valor  el cambio se refleja de forma automática en la UI, también si a la inversa la presentación del dato cambia en la UI los cambios tienen reflejo en la lógica de negocio interna (el contenido de un TextBox modificado por el usuario por ejemplo) .

El modelo MVVM estructura la aplicación en 3 capas:

  • Model: Mantiene los orígenes de datos.
  • ViewModel: Actúa de conector entre las otras dos capas.
  • View: Mantiene la información de la UI.

MVVMBasicDemo1: Primera aplicación

Este es el ejemplo mas sencillo que he encontrado para entender los fundamentos básicos de MVVM con WPF.  La única ventana de la aplicación muestra el nombre y apellido (cada uno en su respectivo TextBox editable) de una lista de estudiantes, junto a los dos TexBox (FirstName y LastName) hay un TextBlock con el nombre y apellidos unidos (FullName), cuando el usuario modifica el nombre o apellido de un estudiante inmediatamente la modificación se actualiza de forma automática en el TexBox (de lectura). Los controles con la lista de usuarios se crean de forma dinámica dependiendo de la lista de estudiantes que proporcionemos en la capa ViewModel.

 

Creamos un nuevo proyecto de tipo “WPF Application” en VS (Visual Studio). Creamos 3 carpetas (Model, ViewModel, Views)

Model

Añadimos una nueva clase “StudentModel” a la carpeta “Model”.

Para poder usar las técnicas de programación que se describen a continuación debemos añadir al comienzo del fichero un nuevo espacio de nombres System.ComponentModel.

using System.ComponentModel;

La clase base ‘INotifyPropertyChanged‘ notifica que el valor de una propiedad ha cambiado, genera un evento PropertyChanged cuando cambia el valor de un miembro de la clase. Debemos definir un atributo de tipo PropertyChangedEventHandler como manejador del evento para notificar a las clases cuando cambia una propiedad en alguno de los atributos editables (firstName,lastName).

Los atributos privados de la clase son el nombre y apellido, controlamos el acceso a sus propiedades con los descriptores de acceso get/set (ver más sobre este tema en “C# class LibroCalificaciones: Acceso a propiedades con descriptores de acceso get / set“), de esta forma controlamos cuando cambia el valor y lanzamos la función RaisePropertyChanged que a su vez llama a al manejador PropertyChanged. El resto de código y comprobaciones que realiza con fáciles de comprender. Si por ejemplo cambia el nombre genera un evento adicional para que en coherencia cambie el FullName.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.ComponentModel;

namespace MVVMBasicDemo1.Model
{
public class StudentModel { }

public class Student : INotifyPropertyChanged
{
private string firstName;
private string lastName;

public string FirstName
{
get
{
return firstName;
}

set
{
if (firstName != value)
{
firstName = value;
RaisePropertyChanged("FirstName");
RaisePropertyChanged("FullName");
}
}
}

public string LastName
{
get { return lastName; }

set
{
if (lastName != value)
{
lastName = value;
RaisePropertyChanged("LastName");
RaisePropertyChanged("FullName");
}
}
}

public string FullName
{
get
{
return firstName + " " + lastName;
}
}

public event PropertyChangedEventHandler PropertyChanged;

private void RaisePropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}

 

ViewModel

En la capa intermedia ViewModel añadimos la clase StudentViewModel.cs. La clase representa el origen de datos de donde se nutre con la lista de alumnos.

La clase StudentViewModel contiene un solo atributo público de tipo Clase ObservableCollection<T>  esta clase representa una colección de datos dinámicos de la clase Student definida en el modelo de datos. El método público LoadStudents() carga la colección de datos con la información de los estudiantes.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using MVVMBasicDemo1.Model;
using System.Collections.ObjectModel;

namespace MVVMBasicDemo1.ViewModel
{
class StudentViewModel
{
public ObservableCollection<Student> Students
{
get;
set;
}

public void LoadStudents()
{
ObservableCollection<Student> students = new ObservableCollection<Student>();

students.Add(new Student { FirstName = "Mark", LastName = "Allain" });
students.Add(new Student { FirstName = "Allen", LastName = "Brown" });
students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" });
students.Add(new Student { FirstName = "Iker", LastName = "Landajuela" });

Students = students;
}
}
}

Views

Lo primero hemos movido el archivo MainWindow.xaml a la carpeta Views donde debería estar.

App.xaml es el punto de entrada cuando arranca la aplicación, VS lo genera de forma automática cuando creamos el proyecto de tipo WPF.

En este fichero debemos modificar el atributo StartupUri para que apunte a  MainWindow.xaml dentro de la carpeta Views. Si quisiéramos mostrar otra ventana en el inicio de la aplicación la definimos en este campo.

App.xaml incluye también por detrás código en el fichero App.xaml.cs (clase Application).

 

MainWindow.xaml

Este fichero contiene la definición de la ventana de nuestra aplicación usando XAML y la etiqueta Window. Definimos algunas propiedades básicas como el tamaño de ventana y el título.

Dentro de Window definimos un control Grid, este control define una rejilla donde alojamos controles en las casillas (Ver The Grid Control). En nuestro caso sólo contiene una vista con la etiqueta views que se encarga de cargar nuestra vista StudentView.xaml.

StudentView.xaml

He añadido un nuevo elemento de tipo “User Control (WPF)” al proyecto en la carpeta Views.  El archivo StudentView.xaml contiene los controles para visualizar la lista de estudiantes, la etiqueta principal UserControl contiene un Grid, dentro un control StackPanel (Ver “WPF StackPanel“).

El control ItemsControl es donde opera la magia del data-binding, se asocia a la propiedad Students (colección de clases Student) definida en la clase StudentViewModel. Dentro de ItemsControl se define ItemsControl.ItemTemplate que contiene el modelo de visualización de un estudiante.

Cada clase TextBox se asocia a un atributo de la clase student usando la propiedad Text.


<UserControl x:Class = "MVVMBasicDemo1.Views.StudentView"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d = "http://schemas.microsoft.com/expression/blend/2008"
xmlns:local = "clr-namespace:MVVMBasicDemo1.Views"
mc:Ignorable = "d"
d:DesignHeight = "300" d:DesignWidth = "300">

<Grid>
<StackPanel HorizontalAlignment = "Left">

<ItemsControl ItemsSource = "{Binding Path = Students}">

<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}"
Width = "100" Margin = "3 5 3 5"/>

<TextBox Text = "{Binding Path = LastName, Mode = TwoWay}"
Width = "100" Margin = "0 5 3 5"/>

<TextBlock Text = "{Binding Path = FullName, Mode = OneWay}"
Margin = "0 5 3 5"/>

</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>

</ItemsControl>

</StackPanel>
</Grid>

</UserControl>

 

Enlaces externos

Anuncios