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.
1 2 3 4 |
<?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:
1 2 3 4 5 6 7 8 9 10 11 12 |
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ść.
1 2 3 4 5 6 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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}"); } } |
1 2 3 4 5 6 7 8 |
private static void Main(string[] args) { var viewModel = new MyViewModel { Text = "text", Count = 1 }; } |

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