Otra implementación básica del patrón MVVM | Alex Casquete [Link]
es/otra-implementacion-basica-del-patron-mvvm/
Autor / Blog / Eventos / Newsletter
Publicado el 13 de julio de 2010
Desde hace unos días estoy preparando el
examen de certificación en desarrollo de
aplicaciones Windows, y ha sido buscando
información sobre patrones de capa de
presentación, cuando me he percatado de la gran
cantidad de implementaciones y frameworks de
MVVM que existen para WPF y Silverlight.
1 de 7 21/01/2016 0:37
Otra implementación básica del patrón MVVM | Alex Casquete [Link]
Muchas veces, sin embargo, tener tantas
opciones desconcierta a los nuevos
desarrolladores, primero por no conocer las
diferencias entre cada una de estas opciones,
pero sobre todo porque generalmente los
ejemplos de implementación no son sencillos o,
incluso, contienen errores.
Con esta entrada voy a iniciar una serie dedicada
a explicar las distintas implementaciones del
patrón MVVM existentes, los principales
problemas que nos podemos encontrar y cómo
los frameworks de MVVM nos pueden ayudar a
resolverlos. Para comenzar, vamos a sentar las
bases y en esta entrada veremos la
implementación básica del patrón de presentación
en una sencilla aplicación de demostración.
El proyecto WPF del que partimos va a consistir
en una vista (ventana) con cinco controles: cuatro
controles Button y un control ComboBox. Los
botones realizarán cuatro acciones: modificar y
restablecer el título de la ventana y añadir y
eliminar elementos al ComboBox. Al seleccionar
un elemento del ComboBox se mostrará la
descripción, valor y fecha de creación del
elemento.
El patrón MVVM se caracteriza por no utilizar el
code-behind de la vista para realizar una acción
de negocio, que siempre debe ser una
responsabilidad del ViewModel. En nuestro
ejemplo, la vista no tiene ni siquiera el fichero de
code-behind, aunque podemos encontrar algunas
implementaciones que utilizan este código para
2 de 7 21/01/2016 0:37
Otra implementación básica del patrón MVVM | Alex Casquete [Link]
establecer el DataContext. Otra característica es
que la vista siempre se comunica con el
ViewModel mediante binding, utilizando la
propiedad Command de los controles.
Comenzamos creando nuestra clase ViewModel
con la propiedad Title, a la que le asignaremos un
valor en el constructor de la clase. Como es
evidente, esto no es una acción de negocio, este
código podría ir perfectamente en la vista, pero
nos sirve a modo de ejemplo.
class ViewModel ?
{
public string Title { get; set; }
public ViewModel()
{
Title = "My title";
}
}
Ahora creamos la vista a la que añadiremos una
referencia al modelo y además indicaremos que el
DataContext de la ventana es la clase ViewModel
que acabamos de crear.
<Window x:Class="[Link]" ?
xmlns="[Link]
xmlns:x="[Link]
xmlns:viewmodel="clr-namespace:[Link]
Title="{Binding Title}">
<[Link]>
<viewmodel:ViewModel />
</[Link]>
</Window>
Si ejecutamos la aplicación, veremos que el título
de la ventana se muestra correctamente. No está
mal para comenzar, ¿no? ¡Continuemos
añadiendo más funcionalidad!
Hagamos que al pulsar un botón, el título de la
3 de 7 21/01/2016 0:37
Otra implementación básica del patrón MVVM | Alex Casquete [Link]
ventana cambie. Para llevar a cabo esta
funcionalidad vamos a definir un comando
mediante la interfaz ICommand. En el proyecto
podemos encontrar la clase RelayCommand que
implementa la interfaz ICommand. Esta clase nos
permite definir, mediante delegados, un método
que se llamará cuando se invoque el comando y
un método para determinar si el comando se
puede ejecutar. Además la clase tiene el evento
CanExecuteChanged, que es parte de la interfaz
ICommand, que se lanza cuando se producen
cambios que modifiquen si el comando se debe
ejecutar o no y delega en el evento
[Link].
public class RelayCommand : ICommand ?
{
public Predicate<object> CanExecuteDelegate;
public Action<object> ExecuteDelegate;
public bool CanExecute(object parameter)
{
return CanExecuteDelegate(parameter);
}
public event EventHandler CanExecuteChanged
{
add { [Link] += value; }
remove { [Link] -= value;
}
public void Execute(object parameter)
{
ExecuteDelegate(parameter);
}
}
Lo siguiente es definir el comando en el
ViewModel y crear los métodos CanUpdateTitle,
que comprueba que el título tenga menos de 50
carácteres, y el método SetTitle que modifica la
propiedad Title.
public ICommand SetTextCommand ?
{
4 de 7 21/01/2016 0:37
Otra implementación básica del patrón MVVM | Alex Casquete [Link]
get
{
this._SetTitleCommand = new RelayCommand()
{
CanExecuteDelegate = c => CanUpdateTitle(),
ExecuteDelegate = c => SetTitle()
};
return this._SetTitleCommand;
}
}
private bool CanUpdateTitle()
{
return [Link] < 50;
}
private void SetTitle()
{
Title += " grows! ";
}
Para que todo funcione correctamente, y la vista
conozca cuando se produce algún cambio en
alguna propiedad, el ViewModel debe
implementar la interfaz INotifyPropertyChanged
para notificar los cambios mediante el evento
PropertyChanged.
class ViewModel : INotifyPropertyChanged
?
{
public event PropertyChangedEventHandler PropertyChange
protected void NotifyPropertyChanged(String propertyNam
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventA
}
}
}
Cómo esta funcionalidad es común a todos los
ViewModels, una buena práctica es crear una
clase base y hacer que todos nuestros
ViewModels hereden de ella. En nuestro ejemplo,
por simplificar al máximo, todo está en una única
clase.
Ahora, en la propiedad Title debemos llamar al
5 de 7 21/01/2016 0:37
Otra implementación básica del patrón MVVM | Alex Casquete [Link]
método PropertyChanged pasando el nombre de
la propiedad que se ha modificado.
public string Title ?
{
get { return _title;}
set
{
_title = value;
NotifyPropertyChanged("Title");
}
}
Y crear el botón en la vista:
<Button Command="{Binding SetTitleCommand}"
?
Para terminar, vamos a ver como enlazar desde la
vista un control ComboBox.
<ComboBox DisplayMemberPath="Name" ItemsSource
?
En la propiedad ItemsSource indicamos la
colección Items de nuestro ViewModel y con la
propiedad DisplayMemberPath le indicamos la
propiedad que debe mostrar. La colección Items
es una ObservableCollection. Añadir ahora un
botón que añada un nuevo elemento a esta
colección, no debería ser tarea difícil.
public ICommand AddItemCommand ?
{
get
{
this._AddItemCommand = new RelayCommand()
{
CanExecuteDelegate = p => true
ExecuteDelegate = p => AddItem()
};
return this._AddItemCommand;
}
}
private void AddItem()
{
Model newItem = new Model();
[Link] = [Link] == 0 ? 1 : Items[[Link]
6 de 7 21/01/2016 0:37
Otra implementación básica del patrón MVVM | Alex Casquete [Link]
[Link] = "Item #" + [Link];
[Link](newItem);
NotifyPropertyChanged("Items");
}
Sólo queda que al seleccionar un elemento del
ComboBox nos muestre en un TextBlock la
información del elemento seleccionado. Esto lo
hacemos enlazando la propiedad SelectedItem
del ComboBox con su homónima del ViewModel.
<ComboBox Name="cmbItems" ?
SelectedValuePath="Value" DisplayMemberPath
ItemsSource="{Binding Items}" SelectedItem
<TextBlock Name="textBlock1" Text="{Binding SelectedItem}"
Hasta aquí esta primera introducción al patrón
Model View ViewModel en WPF. Como he dicho
al principio, seguiré dedicando los próximos posts
a la mejora de esta implementación del patrón y al
funcionamiento de los muchos frameworks de
MVVM que tenemos disponibles.
0 0 0
5 comentarios
7 de 7 21/01/2016 0:37