Tutorial MVVM VI

Tutorial MVVM VI

El ViewModel es la parte del patrón MVVM dónde vamos a establecer las distintas propiedades públicas que se van a enlazar a la Vista, así como los distintos comandos de la lógica de presentación.

Depende de quién sea el desarrollador, hay varias convenciones a la hora de nombrar los ficheros del ViewModel. A mi personalmente me gusta crear un namespace llamado ViewModel, pero a otros les gusta llamar a las clases con el sufijo (o prefijo) VM o ViewModel.

Tutorial MVVM VI

Agregamos tres clases nuevas al proyecto, Search, Weather y MainWindow, que van a ser las que utilizaremos para el ViewModel.

INotifyPropertyChanged

Esta interfaz, es fundamental en el patrón MVVM, nos permite actualizar los elementos de la vista que están enlazados a propiedades en la vista-modelo, para ello basta con implementarla en la ViewModel y al modificarse una propiedad lanzamos  el evento del cambio. Por ejemplo algo así:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace WeatherApp.ViewModel
{
    public class MainWindow : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }

        private String _sample;
        public String Sample
        {
            get { return _sample; }
            set
            {
                _sample = value;
                OnPropertyChanged("Sample");
            }
        }
    }
}

Al realizar cualquier cambio en la propiedad «Sample» automáticamente se reproduce el cambio en la propiedad o propiedades que la tengan enlazada en la Vista, bueno y siendo rigurosos también dependiendo del modo en que esté enlazado, pero en principio asumimos un modo de enlace «TwoWay».

ICommand

Esta interfaz, dispone de tres miembros (un método, un booleano y un manejador de evento), y es el mecanismo a través del cual los distintos controles del XAML van a realizar operaciones, la ventaja fundamental de esta interfaz frente a los eventos, es que no deja de ser una propiedad en la vista-modelo, y por tanto podremos enlazarlos con la vista y reutilizarlos.

using System;
using System.Windows.Input;

namespace WeatherApp.ViewModel
{
    public class Weather : ICommand
    {
        public void Execute(object parameter)
        {
            throw new NotImplementedException();
        }

        public bool CanExecute(object parameter)
        {
            throw new NotImplementedException();
        }

        public event EventHandler CanExecuteChanged;
    }
}

El método es la lógica de la acción, la función booleana es un «flag» que permite ejecutar el comando, y bueno el manejador controla la ejecución del comando.

Implementando las interfaces

Pero…, si tengo que implementar todo este código por cada acción de la aplicación, o para establecer la notificación de las propiedades de cada clase, ¿dónde está el beneficio?. Pues evidentemente esto para una aplicación sencilla con pocos comandos y con pocas vistas-modelos, es algo asequible, pero para aplicaciones más complejas, conviene elaborar una clase que delegue la implementación del «ICommand», y a la que podamos enviar la ejecución de la acción y sus parámetros.

using System;
using System.Diagnostics;
using System.Windows.Input;

namespace WeatherApp.Common
{
    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Predicate<object> _canExecute;

        public RelayCommand(Action<object> execute) : this(execute, null)
        {
        }

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            if (execute == null)
            {
                throw new ArgumentNullException("execute");
            }
            _execute = execute;
            _canExecute = canExecute;
        }

        [DebuggerStepThrough]
        public bool CanExecute(object parameters)
        {
            return _canExecute == null || _canExecute(parameters);
        }

        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object parameters)
        {
            _execute(parameters);
        }
    }
}

Para la notificación de propiedades, generaríamos una clase abstracta, que implementase en un método público, «INotifyPropertyChanged», y después cada clase del ViewModel implementaría esta clase abstracta, llamando únicamente al método que lanza la implementación.

using System.ComponentModel;

namespace WeatherApp.Common
{
    public abstract class ObservableObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }
    }
}

Después de implementar todo esto, en el siguiente post, toca empezar a agregar las propiedades al ViewModel, establecer la notificación de los cambios para que cuando se produzcan se actualicen inmediatamente en la vista, y enlazarlas al marcado XAML mediante el contexto de datos y los Binding.