Tworzenie logiki współdzielonej cz. 2 – MVVM

W poprzednim poście mówiłem o nowym rodzaju biblioteki, jakim jest Portable Class Library. Microsoft przedstawił nam takie rozwiązanie, jeśli chodzi o tworzenie logiki aplikacji mobilnych, do którego musimy się dostosować. W poniższym poście pokaże na przykładzie, że nie jest to takie straszne, a tworzenie logiki za pomocą PCL’a może być całkiem miłe.

Wspominałem wcześniej, że do PLC-a możemy przenieść część naszych ViewModeli, jeśli są one jednakowe w obu aplikacjach (Windows Phone, Windows 8). Możemy to zrobić w prosty sposób: dodać referencję w obu projektach do biblioteki PCL. Postaram się jednak pokazać na przykładzie jak dodawać ViewModele za pomocą prostego wzorca Inversion of Control, jakie daje nam biblioteka MVVMLight.

Na początek tworzymy sobie solucję, która zawierać będzie 3 projekty:

  • PCL – biblioteka  wspólna
  • PCL.WP8 – aplikacja Windows Phone
  • PCL.W8 – aplikacja Windows Store

W ostatnich dwóch projektach dodajemy referencję do pierwszego i od tej pory możemy zacząć dewelopować.

Części wspólne

Zacznijmy więc od projektu PCL. W poprzedniej części wkleiłem obrazek który pokazywał, że w tym rodzaju biblioteki powinniśmy przechowywać modele, viewmodele i interfejsy ujednolicające API Windows Store oraz Windows Phone. Dajmy na to, że chcemy w jednym z naszych ViewModeli zapisywać i odczytywać kontekst naszej aplikacji z pliku. Na Windows Phone plik taki będziemy przechowywać w IsolatedStorage, natomiast w aplikacji Windows Store, w Storage’u dla aplikacji. W takim razie możemy stworzyć sobie interfejs IDataSerializer, który zserializuje nam obiekt konkretnej klasy.

public interface IDataSerializer
{
    Task<ApplicationContext> LoadData();

    void SaveData(ApplicationContext context);
}

Ok, problem się zaczyna, kiedy chcemy w biblitece PCL rzeczywiście coś zapisać. Przecież nie możemy napisać var serializer = new IDataSerializer(). Potrzebujemy konkretnej implementacji. Do tego właśnie posłuży nam wzorzec Inversion Of Control. Wystarczy, że dodamy do wszystkich naszych projektów jakie stworzyliśmy do tej pory bibliotekę MVVM Light Libaries only (PCL). 


mvvmlightnuget

Uważajcie żeby nie dodawać innych bibliotek MVVM Light, bo potem mogą wyniknąć problemy z referencjami.

Następnie mając już dodane wszystkie referencje możemy pobrać konkretną instancję naszego interfejsu w taki oto sposób:

var dataSerializer = ServiceLocator.Current.GetInstance<IDataSerializer>();
var appContext = await dataSerializer.LoadData();

Na chwilę obecną nie interesuje nas czy to zapisuje do pamięci telefonu czy na dysk. Pobieramy konkretną implementację i ładujemy dane. Pierwsze pytanie, jakie się nasuwa to: “Ok, ale gdzie my to wstrzykujemy”. Właśnie, żeby wstrzyknąć konkretną implementację przechodzimy na początek do aplikacji Windows Phone i wykonujemy następujące kroki:

  1. Tworzymy klasę ViewModelLocator
  2. Dodajemy statyczny konstruktor dla tej klasy i w środku wstrzykujemy naszą własną implementację zdefiniowanego wcześniej interfejsu (1):
    static ViewModelLocator()
    {
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        SimpleIoc.Default.Register<IDataSerializer, WPDataSerializer>();  //1
    }
  3. W pliku App.xaml dodajemy do Application Resources definicję naszej klasy, aby przy starcie aplikacji wykonał się nam konstruktor:
    <Application.Resources>
        <vm:ViewModelLocator x:Key="Locator" />
    </Application.Resources>

Identyczne kroki powtarzamy dla aplikacji Windows Store, przy czym podajemy mu inną implementację naszego interfejsu.

Po wykonaniu tych 3 kroków wszystko jest już gotowe. Jeśli uruchomimy aplikacje Windows Phone, to logika w PCLu skorzysta z WPDataSerializer, natomiast jeśli uruchomimy aplikację Windows Store, ServiceLocator zwróci nam obiekt W8DataSerializer (czy jak tam go sobie nazwiemy).

ViewModele

Tutaj praktycznie kończy się nasza wiedza potrzebna do zaimplementowania PCL-a. Natomiast chciałbym również pokazać jak MVVM Light pozwala na wstrzykiwanie ViewModeli do widoków. Czasami chcemy aby dla jednej strony powstała tylko jedna instancja ViewModel i za każdym wejściem na tę stronę otwierał się ten sam obiekt, a nie nowy. Ja wcześniej to załatwiałem poprzez tworzenie statycznej właściwości w App.xaml.cs i pobierania ViewModelu stamtąd. Natomiast mając już zaimplementowane IoC możemy to zrobić w trochę inny sposób. Sposób ten działa zarówno dla WP jak i W8:

  1. W naszym pliku ViewModelLocator dodajemy (1 – jeśli chcemy stworzyć jedną instancję ViewModelu, 2 – jeśli chcemy tworzyć zawsze nową instancję)
    //1
    public HomeViewModel Home
    {
        get
        {
            return ServiceLocator.Current.GetInstance<HomeViewModel>();
        }
    }
    
    //2
    public HomeViewModel Home
    {
        get
        {
            return new HomeViewModel();
        }
    }
  2. W widoku dodajemy do głównego elementu (PhoneApplicationPage – WP, Page – W8) taki atrybut:
    DataContext="{Binding Home, Source={StaticResource Locator}}"

PS. Zacząłem tworzyć bibliotekę wystawiającą interfejsy dla podobnych części systemu Windows Phone oraz Windows 8, natomiast podczas jej pisania zauważyłem, że oba te system tak bardzo się jeszcze różnią, że nie potrafię wielu rzeczy połączyć w jeden interfejs. Możliwe, że niedługo dopiszę brakujące rzeczy i wtedy wrzucę ją na github’a.

PS2. Mam w planach nakręcić filmik pokazujący w trochę bardziej praktyczny sposób połączenie ze sobą tych dwóch aplikacji, natomiast brak czasu i brak pomysłu na taki filmik trochę mnie zatrzymuje.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *