Fody PropertyChanged. Haciendo más llevadero MVVM

¡Hola!
Cuando utilizamos por ejemplo WPF con MVVM, siempre es poco un tedioso añadir en los setters de las propiedades el famoso OnPropertyChanged en sus diferentes sabores. Podemos tener por ejemplo algo así:

public class NotificationObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
public class Person: NotificationObject 
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (name == value) return;
            name = value;
            OnPropertyChanged("Name");
            OnPropertyChanged("FullName");
        }
    }
 
    private string firstSurname;
    public string FirstSurname
    {
        get { return firstSurname; }
        set
        {
            if (firstSurname == value) return;
            firstSurname = value;
            OnPropertyChanged("FirstSurname");
            OnPropertyChanged("FullName");
        }
    }
 
    private string secondSurname;
    public string SecondSurname
    {
        get { return secondSurname; }
        set
        {
            if (secondSurname== value) return;
            secondSurname= value;
            OnPropertyChanged("SecondSurname");
            OnPropertyChanged("FullName");
        }
    }
 
    public string FullName
    {
        get
        {
            return string.Concat(FirstSurname, " ", SecondSurname, ", ", Name);
        }
    }
}

Como vemos en el código anterior (mejorable), para cada propiedad tenemos que hacer el OnPropertyChanged y, como FullName se crea a partir de las otras 3 propiedades, también debemos hacer explícito el OnPropertyChanged de FullName. Para hacer más ágil y limpio la creación de este tipo de clases podemos utilizar Fody.
Lo primero que debemos hacer es añadirlo. Podemos hacerlo vía NuGet:

PM> Install-Package PropertyChanged.Fody

Cuando descarguemos el paquete vía NuGet vamos a ver que nos ha añadido un nuevo archivo al proyecto «FodyWeavers.xml». En este archivo tenemos que especificar que queremos utilizar PropertyChanged.

FodyWeavers

Ahora vamos a cambiar el código anterior por el siguiente:

public class NotificationObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;    
}
public class Person: NotificationObject 
{
    public string Name { get; set; }
    public string FirstSurname { get; set; }
    public string SecondSurname { get; set; }
    public string FullName
    {
        get
        {
            return string.Concat(FirstSurname, " ", SecondSurname, ", ", Name);
        }
    }  
}

Si nos fijamos, hemos quitado de la clase NotificationObject el método OnPropertyChanged, y en cada propiedad de Person hemos eliminado el OnPropertyChanged. Va a ser el propio Fody el que genere la clase con los OnPropertyChanged al compilar, ¡magia!. Incluso en la propiedad FullName, Fody va a darse cuenta de que depende de las otras tres propiedades y se lanzará el OnPropertyChanged(«FullName») cuando se actualice cualquiera de las otras tres propiedades.

Hay ciertas configuraciones básicas que podemos hacer.
Podemos decorar una propiedad con AlsoNotifyForAttribute para indicar explícitamente que cuando se actualice la propiedad decorada con el atributo, también se haga la que se indica en el atributo.

[AlsoNotifyFor("FullName")]
public string Name { get; set; }

O a la inversa, si decoramos FullName con DependsOn, indicamos que cada vez que se actualice alguna de las propiedades indicadas en DependsOn, se actualice FullName.

[DependsOn("Name","FirstSurname","SecondSurname ")]
public string FullName { get; set; }

También nos permite poner un Interceptor global para interceptar cada vez que se llame a OnPropertyChanged. Para ello tenemos que añadir (dentro del ensamblado) una clase estática llamada PropertyChangedNotificationInterceptor.

public static class PropertyChangedNotificationInterceptor
{
    public static void Intercept(object target, Action onPropertyChangedAction, string propertyName, object before, object after)
    {
        Console.WriteLine(string.Concat("La propiedad ", propertyName, " cambia de valor ", before?.ToString(), " a ", after?.ToString()));
        onPropertyChangedAction();
    }
}

Como salida quedaría algo así:

PropertyChangedNotificationInterceptor

Se puede indicar propiedades que no deben notificar cambios, tener dentro de la clase un método con un nombre similar que se llamará al actualizar la propiedad, etc.. La documentación está genial.

¡Saludos¡

Deja un comentario

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