Project Track – MVVM i chodzenie na oślep

Drugi tydzień konkursu więc wypadałoby zacząć na poważnie kodowanie. Problem tylko taki, że na stworzeniu projektu moja wiedza na temat Xamarina się kończy. Oj ten projekt nie będzie taki prosty jakby się mogło wydawać 🙂

W zeszłym tygodniu udało mi się stworzyć projekt Xamarin.Forms Portable z apkami dla Androida, iOSa i Windowsa. Nie obyło się bez problemów, bo jak się okazało Xamarin jest na tyle dynamicznie tworzony, że co chwila pojawiają się jakieś update’y i ot tak stworzyć projekt i go odpalić to się nie da. A to sypie jakimiś dziwnymi błędami, a to każe coś zakualizować, a to po aktualizacjach znowu coś nie działa. No miałem już ochotę to rzucić w pewnym momencie. Okazało się, że po prostu trzeba pobrać paczkę ze strony Xamarina, poczekać aż zaciągnie gigabajty danych (przede wszystkim dla Androida), zainstaluje się to wszystko, potem jeszcze zmiana wersji JDK i wszystko śmiga. Banalne co? Po tym wszystkim stwierdziłem, że Microsoft do tej pory nas trochę rozpieszczał z tym, że instalujemy Visual Studio i już wszystko działa 🙂

No ale ostatecznie się udało i można było zacząć zabawę. Początkowa aplikacja z napisem Hello Xamarin się wyświetla więc jedziemy dalej. No właśnie tyko co dalej?

To co już wiedziałem to to, że Xamarin jest napisany tak żeby wspierać MVVM. Miałem taki rok w swojej karierze w którym pisałem aplikację w Silverlight więc wiedziałem mniej więcej co to za wzorzec, wiedziałem, że będę używał XAMLa, ale szczerze (?) nic z tego nie pamiętam.

MVVM Light

Po krótkim researchu postanowiłem dociągnąć sobie MVVM Light i na tej bibliotece oprzeć strukturę aplikacji. Powstał szybko ViewModelLocator i podstawowy ViewModel i znowu moja wiedza się skończyła. Na szczęście Internet przyszedł z pomocą.

Przejrzałem pobieżnie kilka tutoriali i guide’ów i zaczął powstawać zarys tego jak to powinno wyglądać.

Na początek stoper

W związku z tym, że aplikacja ma liczyć czas spędzony na zadaniu to postanowiłem zacząć od napisania prostego zliczacza czasu. Teoria prosta.

  • Klikam przycisk Start i pobieram DateTime.Now
  • Klikam przycisk Stop, pobieram DateTime.Now i robię TimeSpan z różnicy.

Ok. Ale po pierwsze nie wiem jak w MVVM przekazać tzw. OnClick, po drugie byłoby super gdyby lecący czas na żywo aktualizował się na ekranie telefonu, a po trzecie chciałbym mieć jeden przycisk który zmienia swój tekst po kliknięciach

Znowu szybki skok do Internetu i…

Commandy

Szybko przypomniałem sobie, że w takiej architekturze polega się na Commandach. W widoku przy moim przycisku dopisuję sobie kilka atrybutów:

<StackLayout>
        <Button Text="{Binding Parameter}" Command="{Binding StopWatchCommand}" CommandParameter="{Binding Parameter}"></Button>
    </StackLayout>

I w ViewModelu mogę to sobie bez problemu obsłużyć.

public ICommand StopWatchCommand
        {
            get
            {
                return new Command(() =>
                {
                    StopWatch stopWatch;
                    if (Parameter.Equals("Start"))
                    {
                        stopWatch = new StopWatch();
                        _controlTimer = true;
                        stopWatch.Start = DateTime.Now;
                        Parameter = "Stop";
                        Device.StartTimer(TimeSpan.FromSeconds(1), () =>
                        {
                            stopWatch.End = DateTime.Now;
                            stopWatch.Time = stopWatch.End - stopWatch.Start;
                            TimeString = string.Format("{0:hh\\:mm\\:ss}", stopWatch.Time);
                            if (!_controlTimer) return false;
                            return true;
                        });
                    }
                    else
                    {
                        _controlTimer = false;
                        Parameter = "Start";
                    }
                });
            }
        }

Przy okazji w tym kodzie widać jeszcze jedną rzecz którą chciałem osiągnąć.

Device.StartTimer

Device.StartTimer to taki ciekawy obiekt, który przy zadanym interwale robi określone czynności. Moim przypadku póki co jest to każdorazowe wyliczenie TimeSpana i zaktualizowanie TimeStringa. A co to ten TimeString? Tutaj dochodzimy do ostatniej sprawy.

INotificationPropertyChanged

W architekturze MVVM i w XAMLu istnieje takie pojęcie jak Binding. W ViewModelu tworzę sobie właściwości najróżniejszych typów i za pomocą RaisePropertyChanged() daję znać widokowi, że coś się zmieniło i należy zmienić to co jest aktualnie wyświetlane.

W moim przypadku wygląda to tak:

private string _timeString;
        public string TimeString
        {
            get
            {
                return _timeString;
            }

            set
            {
                _timeString = value;
                OnPropertyChanged();
            }
        }

w ViewModelu.

I tak:

<Label Text="{Binding TimeString}" HorizontalOptions="Center"/>

w widoku.

Ufff no i wszystko się w końcu udało. Aplikacja jeszcze nie powala swoją funkcjonalnością, ale jestem zadowolony, że udało się uzyskać taki efekt:

GIF

Podsumowanie pierwszych kroków

Jak już wspomniałem nie sądziłem, że wejście w Xamarina będzie dla mnie takie trudne. Muszę nauczyć się wyszukiwać dokładnie takich informacji jakich potrzebuję i trochę przyzwyczaić się do tego, że jest to zupełnie inny sposób pisania niż w webie i MVC.

To co mnie baaaardzo cieszy to to, że tak powstaje sobie ta aplikacja, a ja jeszcze nie dotknąłem projektów odpowiedzialnych za samą aplikację Androidową, czy iOSową. Mam nadzieję, że zostanie tak jak najdłużej, bo nie chciałbym za bardzo póki co wchodzić w specyficzne dla każdej platformy detale.

Na koniec plan na przyszłe tygodnie

W kolejnych tygodniach przydałoby się zintegrować z Nozbe. Widziałem, że wystawiają oni jakieś API Restowe, ale chyba skontaktuję się z Michałem Śliwińskim i zespołem z Nozbe, bo stoi to pod jakimiś dziwnym adresem, który przekierowuje na jakąś archaiczną wersję ich aplikacji i nie wiem do końca czy to co tam jest zawarte jest aktualne.

Jak już uda się połączyć z API to trzeba będzie podciągnąć sobie projekty z mojego konta i potem wszystko to jakoś obsłużyć.

No ale to jest plan na przyszły tydzień. Na razie wracam do Xamarin Guide przeplatanego książką do MCSD 70-480 i uczę się dalej. Trzymajcie kciuki 🙂

Related posts

  • Pingback: dotnetomaniak.pl()

  • Aż łezka mi się w oku kręci jak widzę commandy 🙂 dobre 3 lata życia na tym spędziłem i miło to wspominam.
    Patrząc po blogach uczestników konkursu widzę, że nie tylko ja mam początkowe trudności.
    Pozdrawiam i powodzenia

    • Kajetan Duszyński

      Hmmm, ja aż tak dobrze nie wspominam swoich początków z commandami. Może tym razem pójdzie lepiej i oby to były jedne z ostatnich problemów 🙂

  • janko

    W takim razie co do początków z komendami. CommandParameter służy do tego, żeby przekazać jakieś parametry w komendzie. Twoja komenda ma zaś postać () => { } ,czyli komendy bezparametrowej. Dlatego ten binding CommandParameter w widoku jest zbędny. Ponadto polecałbym, żeby komendom przypisywać jednak metody i robić to w konstruktorze ViewModelu, wtedy wyraźnie byłoby widać że np. StopWatchCommand = new DelegateCommand(OnStopWatch) przyjmuje parametr i ten kod byłby trochę bardziej elegancki albo w przyszłości re-używalny. Pozmieniałbym też nazwy, szczególnie to Parameter na coś w stylu StopwatchState oraz zamienił „string” w nazwie TimeString na coś innego, bo używanie nazw typów w nazwach jest niepożądane jak to rzecze m.in. Uncle Bob 😉
    Pozdrawiam i również życzę powodzenia

    • Kajetan Duszyński

      Tak z tym CommandParameter to tak próbowałem na różne strony i w sumie faktycznie nie jest używany. Dzięki za podpowiedź z metodami. Na pewno będę tak robił od tej pory. No i jeśli chodzi o nazwy to oczywiście będę zmieniał. Na tę chwilę to tak powrzucałem żeby zobaczyć czy działa.

      Tak czy inaczej wielkie dzięki za wskazówki 🙂 na pewno się przydadzą.