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.

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:

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ść.

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.

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

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

ActionResult – ASP.NET Core Web API

W Web Api przy użyciu dotnet core dane mogą być zwrócone na kilka sposobów.

Zwracany typ

Pierwszy, najprostszy sposób, metoda w kontrolerze zwraca dane typu np. IEnumerable<string>. Najszybsze i najprostsze rozwiązania, niestety, jeśli chcemy zwrócić jakąś inną odpowiedź http niż OK to za bardzo nie mamy takiej możliwości. Korzystając na przykład z return BadRequest() dostaniemy błąd kompilacji że zwracany typ się nie zgadza.

IActionResult

IActionResult zezwala na zwracanie różnych odpowiedzi http w zależności od potrzeb. W tym wypadku, nie jesteśmy w stanie zwrócić już bezpośrednio kolekcji, musimy ją opakować w odpowiedź OK().

IActionResult<T>

Typ wprowadzony w ASP.NET Core 2.1, łączy dwa powyższe rozwiązania. Korzystając z tego typu, mamy gwarancję że nasza metoda zwróci na pewno żądany typ, na przykład IEnumerable<string>. Dodatkowo w zależności od zapotrzebowania możemy zwrócić inne odpowiedzi http.

Kod z posta dostępny na github – link

Xamarin.Forms + Prism – Dependency Injection

Wstęp

Dzisiejszy post będzie troszkę nawiązywał do poprzedniego, o dependency injection link.Xamarin Forms nie posiada żadnego wbudowanego mechanizmu do dependency injection więc aby to osiągnąć potrzebujemy dodatkowych bibliotek. Ja w swoim projekcie korzystam z Prism. Autorzy biblioteki utworzyli warstwę abstrakcji Prism.Ioc – jest to zestaw interfejsów do obsługi kontenerów. Dzięki temu rozwiązaniu mogą powstawać pakiety dla kontenerów np. Unity, Ninject itp. Oczywiście jest to tylko teoria, założenie jest słuszne, niestety nie wszystkie kontenery są kompatybilne o czym możemy poczytać w dokumentacji Prism na GitHub – link. Jak już zdecydujemy z którego kontenera chcemy skorzystać to musimy zainstalować odpowiedni pakiet nuget. Ja korzystam z Unity dlatego też przykład będzie w oparciu o ten kontener. Instalujemy paczkę Prism.Forms.Unity. Przedstawiałem już wcześniej jak przygotować projekt do korzystania z Prism – link. Pamiętajmy, że każdy widok z którego chcemy korzystać, musi być zarejestrowany w kontenerze, w metodzie RegisterTypes.

Zależności

Wszystkie zależności rejestrujemy również w metodzie RegisterTypes. Utwórzmy repozytorium IHomeRepository i dodajmy je do naszego HomeViewModelu. Utwórzmy jedną właściwość title i odczytajmy ją z repository.

Ja w przykładzie rozszerzyłem mój view model o interfejs INavigationAware żeby mieć dostęp do metod nawigacji. Kolejny krok to zarejestrowanie IHomeRepository, w App.xaml.cs w metodzie RegisterTypes. W zależności od potrzeb, możemy zarejestrować typ zwyczajnie, jako singleton, a nawet możemy podać konkretną instancję jaka ma być przypisana. TestHomeRepository zwraca po prostu tekst Hello Unity!

Po wykonaniu powyższych kroków, Prism podczas tworzenia obiektu HomeViewModel oraz innych view modeli automatycznie przypisze zarejestrowane wcześniej właściwości.

Przykładowy kod jest dostępny na GitHub – link

Dependency Injection + dotnet core

Podczas pisania kodu czeka nas bardzo dużo problemów do rozwiązania. Pierwsze kawałki kodu zazwyczaj wyglądały tak, że wszystko było pisane w jednej metodzie lub klasie. Następnie, po przeczytaniu paru książek/artykułów, człowiek zaczął bardziej się zastanawiać nad tym co robi. Podział kodu na klasy: repozytoria, managery, serwisy, i wszystkie inne. Następnie pojawia się problem, jak połączyć te klasy ze sobą.

Dependency Injection

Zakładając że mamy klasę CustomersService która korzysta z repozytorium CustomersRepository, to w takim wypadku repository jest zależnością w serwisie. 

Powyższy kod będzie działał ale problem się zacznie pojawiać jeśli będziemy chcieli napisać unit testy albo zmienić data source naszego repository. Z pomocą przychodzi dependency injection, wzorzec który odwraca trochę sytuacje i mówi że mamy przekazywać gotowe komponenty zamiast je tworzyć wewnątrz klasy. Możemy je przekazać na przykład przez konstruktor lub jako właściwości. Przerabiając nasz przykład, zamienimy tworzenie instancji CustomersRepository na przekazanie interfejsu ICustomersRepository.

Po zmianach, możemy swobodnie zacząć pisać unit testy oraz CustomersService nie korzysta teraz z konkretnego CustomersRepository tylko z elastycznego rozwiązania przez interfejs. 

Kontenery

Kontenery są to specjalne klasy które odpowiadają za zarządzanie zależnościami. W skrócie mówiąc, można w nich rejestrować typy oraz tworzyć nowe instancje zarejestrowanych typów. Ja zaprezentuję jak to jest rozwiązanie w aplikacji asp.net core. Utworzyłem domyślny projekt dla aspnet core web api, rozszerzyłem ValuesController żeby korzystał z IValuesRepository oraz utworzyłem klasę implementującą ten interfejs.

Aby powyższy kod zadziałał, musimy jeszcze w aplikacji/kontenerze zarejestrować IValuesRepository. W aspnet core odbywa się to w klasie Startup.cs w metodzie ConfigureServices. Dodajemy jedną linijkę, czyli mówimy że klasa ValuesRepository ma być podstawiona pod IValuesRepository.

Wiele implementacji

W zależności od potrzeb, możemy zarejestrować wiele implementacji jednego interfejsu. Załóżmy że mamy serwis odpowiedzialny za wysyłanie powiadomień, smsy, email i inne. Przykładowa implementacja może wyglądać tak, tworzymy wspólny intefejs IMessageService z metodą Send(string message). Utwórzmy dwie klasy EmailMessageService oraz TextMessageService, obie implementujące IMessageService. Następnie rejestrujemy je w metodzie ConfigureServices i przekazujemy do kontrolera kolekcję typu IEnumerable<IMessageService>.

Powyższa metoda GetMessageServiceTypes() zwróci wszystkie zarejestrowane typy.

Cały kod dostępny na github –
https://github.com/brzooz/Blog/tree/master/c%23/DependencyInjectionExample

Xamarin.Forms – Prism – binding + ICommand

Wstęp

W dzisiejszym poście chciałbym skupić się na opisie Xamarin.Forms oraz biblioteki Prism. Przedstawię przykład użycia bindingu oraz zastosowanie interfejsu ICommand.

Xamarin.Forms

Xamarin.Forms, warstwa abstrakcji do tworzenia aplikacji pod Android, iOS, Windows oraz macOS. Kod piszemy głównie w dzielonym projekcie a projekty poszczególnych platform tylko go wywołują. Interfejs graficzny piszemy w XAML (jest też możliwość pisania w c#), osoby które miały styczność z WPF, bardzo szybko się odnajdą w Xamarin.Forms, reszta na pewno nie będzie miała większych problemów żeby go opanować. Język XAML sam w sobie niczego nie narzuca ale wspiera wzorzec MVVM i właśnie on jest zalecany podczas pisania aplikacji.

Prism

Pisanie aplikacji w czystym XAML, z użyciem MVVM, jest troszkę skomplikowane na dłuższą metę, dlatego powstały różne frameworki wspomagające MVVM. Jednym z nich jest Prism, framework z początku wykorzystywany do pisania aplikacji w WPF, także projekt ten jest już długo rozwijany. Korzystając z Prism możemy pisać testowalny kod, dodatkowo możemy podzielić naszą aplikację na mniejsze moduły, co pozwala na łatwiejsze zarządzanie kodem.

Dodanie Prism do projektu

Pierwszy krok to utworzenie projektu. Następnie musimy dodać odpowiedni pakiet nuget. Prism korzysta z dependency injection dlatego musimy zdecydować z jakiego kontenera skorzystamy, ja dla przykładu wykorzystam Unity więc potrzebuję nuget Prism.Forms.Unity. O dependency injection na pewno powstanie jakiś post niedługo. Po instalacji pakietu musimy wprowadzić trochę zmian.

App.xaml – Główny znacznik to musi być PrismApplication, żeby to osiągnąć musimy najpierw zaimportować Prism.Unity.Forms

App.xaml.csApp musi dziedziczyć po PrismApplication, implementować klasę abstrakcyjną, oraz wyświetlić jakiś widok, najlepiej korzystając z NavigationService.

Kolejnym krokiem jest utworzenie pierwszego view modelu, dla porządku dodajmy katalog ViewModels i utwórzmy w nim klasę HomeViewModel. Prism opiera się na konwencji nazewniczej, jeśli mamy HomeView i utworzymy HomeViewModel to one się razem sparują. Rozwiązanie to jest elastyczne więc jeśli chcemy podpiąć inny view model to też jesteśmy w stanie to zrobić. Mając utworzony widok oraz view model musimy go zarejestrować w aplikacji, wchodzimy do pliku App.xaml.cs i rozszerzamy ciało metody RegisterTypes:

Przejdźmy do HomeViewModel.cs. Komunikacja pomiędzy widokiem a view modelem odbywa się korzystając z powiązań – bindingu. Wiążemy jakąś właściwość z view modelu z właściwością XAML, na przykład Label.Text. Powiązania korzystają z interfejsu INotifyPropertyChanged który składa się z eventu PropertyChanged. Prism udostępnia nam klasę która implementuje ten interfejs BindableBase i z niej skorzystamy. Tworzymy właściwość Count przechowującą ilość kliknięć przycisku, ważne jest to aby w setterze wywołać event PropertyChanged aby poinformować widok że wartość się zmieniła, do tego służy metoda RaisePropertyChanged(). Potrzebujemy jeszcze funkcję która będzie wywołana po naciśnięciu przycisku, która będzie inkrementować nasz licznik. XAML korzysta z interfejsu ICommand do przekazywania metod, więc musimy utworzyć własciwość typu ICommand i przypisać do niej metodę. Z pomocą przychodzi nam Prism który implementację ICommand zawarł w klasie DelegateCommand.

Pozostaje nam jeszcze powiązać powyższe właściwości z widokiem. Przejdźmy do HomeView.xaml. Tworzymy Label żeby wyświetlić ilość tapnięć oraz przycisk żeby zwiększać licznik. Pierwsze powiązanie będzie z Labelem, do właściwości Text dowiążemy właściwość Count view modelu. Korzystamy tutaj ze słówka Binding. Podobnie sytuacja wygląda z przyciskiem, który posiada właściwość Command.

Podsumowując mamy dwa elementy niezależne od siebie. Widok którego nie interesuje jaki view model jest do niego podpięty, tylko wie że view model ma dostarczyć właściwość Count oraz IncrementCountCommand. Mamy też view model który nic nie wie o tym do jakiego widoku jest podpięty, dzięki takiemu podejściu możemy pisać testy jednostkowe do view modelu.

Kod dostępny na github –
https://github.com/brzooz/Blog/tree/master/Xamarin.Forms/PrismExample

Xamarin.Forms – Content View

Witam. Dzisiejszy post będzie poświęcony Xamarin.Forms. Przedstawię o co chodzi z ContentView na podstawie przykładu z wyświetlaniem imienia.

Content View

Xamarin.Forms umożliwia tworzenie ContentView, własnych kontrolek z których później można korzystać. Dodatkowo te kontrolki można rozszerzać o właściwości, tzw. Bindable Properties. Dla przykładu stwórzmy ContentView który będzie wyświetlać Hello imię. Zawartość kontrolki czyli Content może zawierać tylko jeden „widok”, element który dziedziczy po klasie View. W naszym przykładzie chcemy wyświetlić tylko Hello imię więc potrzebujemy Label który dziedziczy po View. Jeśli chcielibyśmy mieć dwa Labele, to sprawa się już trochę komplikuje i trzeba to opakować np. w StackLayout. Utwórzmy ContentView z nazwą HelloName.

Powyżej zawartość pliku XAML która jest nam potrzebna do wyświetlenia tekstu. Korzystamy tutaj z bindingu który oferuje XAML oraz StringFormat żeby sformatować żądany tekst.

Przejdźmy do kodu. Żeby zrobić elastyczną kontrolkę do której możemy przekazać np. imię potrzebujemy utworzyć BindableProperty. Jest to statyczne pole w klasie które korzysta z właściwości którą również musimy utworzyć.

Parametry funkcji Create które nas interesują:

  • Nazwa właściwości – korzystamy tutaj z nameof
  • Typ właściwości – Name jest typu string.
  • Typ obiektu który posiada właściwość – W tym wypadku będzie to typ naszego ContentView

Na końcu jeszcze trzeba ustawić, w konstruktorze, BindingContext naszej kontrolki na nią samą. Wtedy w XAML będziemy mogli korzystać z naszych właściwości.

Po utworzeniu kontrolki możemy z niej korzystać na naszych widokach. Ja akurat utworzyłem ContentView w katalogu Controls dlatego namespace różni się od namespace’u mojego widoku. Jedyne co to trzeba zaimportować ten namespace i można korzystać z nowej kontrolki.

Działający kod z przykładu można znaleźć pod tym linkiem