Fody + INotifyPropertyChanged

Witajcie, dzisiejszy post będzie poświęcony bibliotece Fody. Biblioteka ta służy do modyfikowania kodu IL przy kompilacji. Sama biblioteka jest praktycznie bezużyteczna, do działania potrzebne są pluginy, można korzystać z napisanych już pluginów lub pisać swoje. Ja przedstawię przykład użycia biblioteki z pluginem NotifyPropertyChanged, z której korzystam w projekcie Xamarin.Forms ale przykład nie będzie na projekcie typu Xamarin, biblioteka jest napisana w dotnet core więc możemy z niej korzystać we wszystkich wspieranych typach projektu!

Fody

Biblioteka jest dostępna na github –
https://github.com/Fody/Fody – tam znajdziecie wszystkie informacje związane z biblioteką. Polecam zapoznać się z sekcją Licensing, zanim zaczniecie korzystać. W przykładzie wykorzystamy wersję 3.3.2, najwyższą której nie dotyczy licencjonowanie. Plugin z którego skorzystamy nazywa się PropertyChanged i projekt jest również dostępny na github –
https://github.com/Fody/PropertyChanged – tutaj warto zwrócić uwagę również na wersję, tak żeby była kompatybilna z wersją fody. Wersja 2.6.0 w zależnościach ma Fody (>= 3.3.2) więc do naszych potrzeb będzie idealna. Po pobraniu odpowiednich pakietów nuget, musimy utworzyć jeszcze plik FodyWeavers.xml i „zarejestrować” w nim plugin.

<?xml version="1.0" encoding="utf-8"?>
<Weavers>
  <PropertyChanged/>
</Weavers>

INotifyPropertyChanged

Każdy kto miał styczność z XAML na pewno się spotkał z tym interfejsem. Jest to interfejs który dostarcza nam event – PropertyChanged, który służy do komunikacji ViewModelu z widokiem, podczas modyfikacji właściwości możemy poinformować nasz widok o tym że wartość się zmieniła. Każda właściwość, którą chcemy aby wysłała zdarzenie, musi wywołać event. Zazwyczaj zapis wygląda w ten sposób:

public string Text
{
    get
    {
        return _text;
    }
    set
    {
        _text = value;
        RaisePropertyChanged();
    }
}

Korzystając z pluginu, nasz kod zamieniamy na zwykłe auto properties. Poniżej klasa którą utworzyłem – implementacja interfejsu, oraz jedna właściwość.

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public string Text { get; set; }
}

Po skompilowaniu, korzystając na przykład z ILSpy, możemy podejrzeć jak wygląda nasza klasa, widzimy że doszła metoda OnPropertyChanged, oraz nasza właściwość ją wywołuje.

public class MyViewModel : INotifyPropertyChanged
{
    [method: CompilerGenerated]
    [DebuggerBrowsable, CompilerGenerated]
    public event PropertyChangedEventHandler PropertyChanged;

    public string Text
    {
        [CompilerGenerated]
        get
        {
            return this.< Text > k__BackingField;
        }
        [CompilerGenerated]
        set
        {
            if (string.Equals(this.< Text > k__BackingField, value, 4))
            {
                return;
            }
            this.< Text > k__BackingField = value;
            this.<> OnPropertyChanged(<> PropertyChangedEventArgs.Text);
        }
    }

    protected void <>OnPropertyChanged(PropertyChangedEventArgs eventArgs)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged.Invoke(this, eventArgs);
        }
    }
}

Po małej modyfikacji naszej klasy oraz main, jesteśmy w stanie zobaczyć że ten kod działa.

public class MyViewModel : INotifyPropertyChanged
{
    public MyViewModel()
    {
        PropertyChanged += MyViewModel_PropertyChanged;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public int Count { get; set; }
    public string Text { get; set; }

    private void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        Console.WriteLine($"Property changed - {e.PropertyName}");
    }
}
private static void Main(string[] args)
{
    var viewModel = new MyViewModel
    {
        Text = "text",
        Count = 1
    };
}

Kod z przykładu dostępny na github – link

Scroll to Top