Szukaj na tym blogu

wtorek, 17 sierpnia 2010

Dziennik Zdrowej Diety – Wzorzec MVVM – Koncepcja

Aplikacja Dziennik Zdrowej Diety jest udostępniona na codeplex, przez co nad rozwojem projektu może pracować wiele osób. Wśród tych osób znajdą się zapewne programiści oraz osoby odpowiedzialne za projektowanie interfejsu użytkownika. By usprawnić pracę pomiędzy te dwie profesje, zastosowałem wzorzec projektowy MVVM (Model-View-ViewModel).
Czym jest wzorzec MVVM ? To wzorzec, stworzony na potrzeby technologii WPF oraz Silverlight, którego zadaniem jest odspearowanie od siebie kolejnych warstwy aplikacji tj.



View – warstwa prezentacji, czyli plik xaml przedstawiający widok formatki z umieszczonymi na niej kontrolkami. Widokiem może być również pojedyńcza kontrolka użytkownika (UserControl).
Rzeczą charakterystyczną takiej formatki w porównaniu do zwykłaej aplikacji nie wykorzystującej wzorca MVVM (lub pokrewnych) jest fakt, że w code behind formatki nie znajduje się żaden kod związany z logiką biznesową. Dopuszczalne jest posiadanie w code behind kodu operującego na interfejsie użytkownika (nie mającego nic wspólnego z logiką biznesową).
Model – model opisuje naszą logikę biznesową. Składa się on obiektów biznesowych przybierających najczęściej postać obiektów POCO ang. Plain Old CLR Object, czyli klas zawierających dane (w postaci property) oraz logikę biznesową (walidatory danych). Model jak i View nie wiedzą o swoim istnieniu.
ViewModel – to obiekt będący łącznikiem pomiędzy modelem (Model), a widokiem (View). To właśnie ten obiekt odpowiada za pobranie właściwych informacji ze źródła danych, udostępnienia ich w odpowiedniej postaci do widoku (Converter) oraz przekazania zaktualizowanych informacji spowrotem do źródła danych. Interakcja widoku z ViewModel odbywa się za pomocą funkcjonalności Bindowania oraz wsparcia wzorca projektowego Command.


Przykład:

Na potrzeby przykładu stworzyłem prosty model zawierający 2 właściwości i jedną walidację.
namespace SimpleMVVM
{
    public class MyModel
    {
        public string NickName { get; set; }
        public string Description { get; set; }
        
        public bool ValidateNickName(string nickname)
        {
            return string.IsNullOrWhiteSpace(nickname);
        }
    }
}

Kolejnym elementem odgrywającym ważną rolę jest ViewModel, który pobiera dane z naszego modelu i udostępnia je na zewnątrz

public class MyViewModel : INotifyPropertyChanged  
    {
        private readonly MyModel myModel;

        public MyViewModel()
        {
            myModel = new MyModel();
        }

        public string Nickname
        {
            get { return myModel.NickName ?? string.Empty; }
            set 
            {
                if (myModel.ValidateNickName(value))
                {
                    myModel.NickName = value;
                    FirePropertyChanged("Nickname");
                }
            }
        }

        public string Description
        {
            get { return myModel.Description; }
            set
            {
                myModel.Description = value;
                myModel.NickName += " Hello!";
                FirePropertyChanged("Nickname");
                FirePropertyChanged("Description");
            }
        }

        protected void FirePropertyChanged(string property)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(property));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

W View deklarujemy nasz ViewModel w następujący sposób
<UserControl.Resources>
        <vm:MyViewModel x:Key="myViewModel" />
        <vm:MyConverter x:Key="myConverter" />
    </UserControl.Resources>

Dodatkowo zadeklarowaliśmy konwerter MyConverter, który ma postać

public class MyConverter : IValueConverter
    {
        public MyConverter()
        {
            
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var msg = value as string;
            if (!string.IsNullOrWhiteSpace(msg) && msg.Contains("Hello!"))
                msg = msg.Replace("Hello!", "Hello World!");
            return msg ?? String.Empty;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return value;
        }
    }

Na koniec bindujemy kontrolki z View z naszym ViewModel
<TextBox Text="{Binding 
                            Source={StaticResource myViewModel}, 
                            Path=Nickname, 
                            Mode=OneWay}"
                 Grid.Column="1"
                 Grid.Row="0"
                 VerticalAlignment="Center"" />

<TextBox Text="{Binding 
                            Source={StaticResource myViewModel}, 
                            Path=Description, 
                            Mode=TwoWay, 
                            Converter={StaticResource myConverter}}"
                 Grid.Column="1"
                 Grid.Row="1"
                 VerticalAlignment="Center" />


Działanie:
Pierwszy TextBox jest zbindowany z właściwością Nickname w MyViewModel. Jest to bindowanie typu OneWay co oznacza, że widok pobiera wartości z ViewModel, a ViewModel nic nie wie o ewentualnych zmianach wartości tego TextBox’a.

Drugi TextBox jest zbindowany z właściwością Description w MyViewModel. Jest to bindowanie typu TwoWay co oznacza, że zarówno widok, jak i ViewModel są informowane o zmianie wartości zbindowanej właściwości. Dodatkowo wartość wysyłana do TextBox’a podlega konwersji w klasie MyConverter.

Efekt:
• wpisujemy w pierwszego TextBox’a tekst „Ala ma kota” – nic się nie dzieje,
• wpisujemy w drugiego TextBox’a tekst „Hello!”
• ustawia się właściwość Description instancji klasy myModel na „Hello!”
• ustawia się właściwość NickName instancji klasy myModel na „ Hello!” (zauważ, że pomimo wpisania w pierwszego TextBox’a wartości „Ala ma kota”, nie ma jej po stronie ViewModel)
• odpalane jest powiadomienie o zmianie właściwości „Description”
• pobierana jest wartość właściwości „Description” z uwzględnieniem konwertera,
• pobierana jest wartość właściwości „Nickname”

Kod źródłowy

Ktoś pewno zada pytanie „Poco to wszystko ?”. Otóż korzystając ze wzorca MVVM poza separacją widoku (projektant) od całej reszty (programista) mamy szereg dodatkowych plusów tj. możliwość stosowania testów jednostkowych, uproszczone zarządzanie kodem, schemat działania pozwalający na systematyczny rozwój aplikacji oraz łatwe wdrożenie nowych programistów do projektu.

Powyższy opis ma na celu ogólne przedstawienie koncepcji tworzenia oprogramowania przy wykorzystaniu wzorca MVVM. Ma to posłużyć większemu zrozumieniu kolejnych kroków związanych z rozwojem aplikacji „Dziennik Zdrowej Diety”.
Po więcej szczegółów odsyłam do artykułu zamieszczonego w MSDN Magazine (http://msdn.microsoft.com/en-us/magazine/dd419663.aspx).

Wartym wspomnienia jest fakt, że wzorzec MVVM zyskał na popularności dzięki czemu wielu programistów zaczęło tworzyć własne rozszerzenia tego wzorca.
I tak np. Calcium wspiera funkcjonalność Undo/Redo, ale jest opracowany tylko dla WPF podczas gdy Cinch nadaje się zarówno do WPF jak i Silverlight i dodatkowo współpracuje z MEF (Managed Extensibility Framework).
By przyjrzeć się zestawieniu frameworków MVVM odysłam pod poniższy adres:
(http://www.japf.fr/silverlight/mvvm/index.html)

czwartek, 12 sierpnia 2010

LinkedIn Silverlight PL Users Group

Założyłem na LinkedIn nową grupę Polskich użytkowników Silverlight.

Chciałbym by w tej grupie można było znaleźć takie rzeczy jak:
- wasze pytania odnośnie napotkanych problemów,
- sugestie związane z ciekawym odkryciem wykorzystania "czegoś",
- informacje na temat spotkań grup Silverlight'owych,
- informacje na temat zbliżających się konferencji, prezentacji (również internetowych),
- linki do ciekawych źródeł dotyczących Silverlight jak np. kolejny odcinek Silverlight TV,
- inne równie interesujące tematy.

Dlaczego akurat na LinkedIn ? Ponieważ serwis ma zasięg globalny dzięki czemu być może któremuś z was uda się znaleźć jakiś ciekawy projekt poza granicami naszego kraju.

Gorąco zapraszam.

środa, 11 sierpnia 2010

Dodatki do Visual Studio - objawienie

Z Visual Studio korzystam już kilka lat, ale dopiero wczoraj w mojej przeglądarce pojawił się link do Visual Studio Gallery. Szkoda, że tak późno.
Poniżej przedstawiam kilka dodatków, które posiadają funkcje jakich do tej pory brakowało mi w Visual Studio.

Search References - dodaje textbox'a pomocnego przy filtrowaniu assembly w okienku do dodawania referencji.


VSGesture.v2 for VS2010
- gesty myszy (cofnij się o dokument, przejdź do następnego dokumenu, zbuduj projekt, uruchom projekt).

Go To Definition - przechodzi do definicji klasy, właściwości, etc. za pomocą skrótu CTRL + MouseClick (tego brakowało mi najbardziej- w Borland Developer Studio można było zbindować Mouse3 do tego typu rzeczy i to było nieocenione).

Open Folder in Windows Explorer - rozszerza menu kontekstowe o możliwość przejścia do folderu, w którym znajduje się dany plik, projekt.

Numbered Bookmarks - numerowane bookmarki z bardzo fajnym sposobem bindowania, odszukiwania (fajny bo taki ale StarCraft-owy ;) ).

Highlight all occurrences of selected word - po zaznaczeniu szukanej frazy w tekście, podświetla wszystkie jej wystąpienia (podobnie jak w Notepad++)

Snipper - dosyć zgrabny tool do zapisywania własnych snippet-ów.

CodeCompare - dosyć rozbudowany comparer kodu z możliwością integracji z TFS, SVN.

Productivity Power Tools - zestaw narzędzi udostępniających wiele ciekawych funkcji tj. Solution Navigator, Ctrl + Click Go to Definition, kopiowanie HTML i wiele innych.

Resource Refactoring Tools 2010 - dzięki temu narzędziu, łatwiej Ci będzie przenieść zahardkodowane stringi do pliku .resx

wtorek, 3 sierpnia 2010

Dziennik Zdrowej Diety – Zarządzanie zasobami

Budując aplikację wielo- modułową (np. Przy wykorzystaniu Prism, MEF) musimy zadbać o zgrabne zarządzanie plikiem przechowującym nasze style, szblony.
Poniżej przedstawiam krótki przykład jak sobie z tym poradzić w Silverlight.

1) Załóżmy, że posiadamy solucję składającą się z kilku projektów.



Każdy z widoków wykorzystuje zestaw kontrolek, na których chcielibyśmy skorzystać z tego samego stylu.

2) Tworzymy nowy projekt Silverlight Class Library, a następnie dodajemy nowy element Silverlight Resource Dictionary (nasz będzie się nazywał DictStyles.xaml)













3) Wszystkie style zapisujemy w tym pliku, a jeśli chcemy z nich skorzystać to do każdego widoku dodajemy sekcję:



gdzie ResourcesStore to nazwa assembly w której znajduje się nasz plik ze stylami, component to słówko stałe, a DictStyles.xaml to nazwa naszego słownika
(po szczegóły na temat odwoływania się do zasobów odsyłam pod ten link: Channel9- Mike Taulty )

4) Teraz tylko wystarczy dodać do każdego projektu referencję do naszej dll’ki i cieszyć się z efektu.

(UWAGA: bardzo ważne by dodać referencję do dll’ki ze stylami w głównym projekci – nawet jeśli nie posiadacie tam nic poza Shell.xaml, App.xaml. Ja zmarnowałem kilka godzin zanim rozgryzłem dlaczego moje moduły w runtime nie widzą styli :/ ).

Edycja 15-08-2010.
By nie rozbijać wątku na dwa tematy dopiszę coś więcej na temat zarządzania zasobami.

Istnieje kilka sposobów dostępu do zasobów:

"myImage.jpg" - aplikacja poszukuje obrazek w assembly umieszczonym w pliku XAP. Jeśli go nie znajdzie to przeszukuje katalog ClientBin. Plik musi mieć ustawioną właściwość:
Build Action = Resource

"/myImage.jpg" - aplikacja poszukuje obrazka w pliku XAP. Jeśli go nie znajdzie to przeszukuje katalog ClientBin. Plik musi mieć ustawioną właściwość:
Build Action = Content

"/MyAssembly;component/Images/myImage.jpg" - aplikacja poszukuje obrazka w katalogu Images znajdującym się w assembly MyAssembly osadzonym w pliku XAP.

"/MyAssembly;component/Fonts/MyFont.ttf#My Font" - aplikacja poszukuje czcionkę w katalogu Fonts znajdującym się w assembly MyAssembly osadzonym w pliku XAP.

"/MyAssembly;component/Fonts/Fonty.zip#My Font" - analogicznie jak powyżej z tym, że przeszukiwane jest archiwum ZIP pod kątem wystąpienia czcionki o nazwie "My Font" (nie mylić z nazwą pliku czcionki).

poniedziałek, 2 sierpnia 2010

Dziennik Zdrowej Diety – SketchFlow

SketchFlow to dodatek do aplikacji Microsoft Expression Blend (wersja 3 i 4). Głównym zadaniem tego dodatku jest wspomożenie programisty przy tworzeniu prototypu interfejsu użytkownika.

Używając SketchFlow możesz:
• tworzyć formatki wykorzystując zestaw kontrolek WPF, Silverlight, SketchFlow,
• tworzyć animamacje i przejścia za pomocą zachowań pomiędzy stanami kontrolek,
• nawigować pomiędzy kolejnymi formatkami,
• wykorzystać przykładowe dane do zasymulowania rzeczywistej aplikacji,
• publikować stworzone rozwiązanie na serwer SharePoint.

W wielkim uproszczeniu SkechFlow mogę porównać do takiego napakowanego PowerPoint’a z większymi możliwościami integracji w tworzone rozwiązania.
Na stronie Microsoft Expression znajdziecie Expression Studio 4 Ultimate w wersji Trial pozwalającej na zabawę z całym pakietem przez 60 dni.

W czym ma nam pomoć SketchFlow ? Jest to szybki sposób na pokazanie klientowi końcowemu jak będzie wyglądał produkt końcowy.
Korzystając z uwag klienta, bardzo szybko możemy nanieść zmiany na taki prototyp dzięki czemu zaoszczędzi nam to wiele nieporozumień przy kolejnej prezentacji. (etapy tworzenia oprogramowania).

Poniżej zamieszczam krótki tutorial mający za zadanie wprowadzenie was w Świat SketchFlow.

1) Uruchamiamy Expression Blend 4. Z menu File -> New Project … wybieramy Silverlight SketchFlow Application

SketchFlow - nowy projekt



2) W wyniku kroku pierwszego otrzymujemy:



Zakładki:
Project – przedstawia nam eksplorator naszej solucji składającej się z 2 projektów. Pojedynczy Szkic (Sketch), na który będziemy tworzyć nasz interfejs, jest kontrolką UserControl w formacie XAML (Screen1.xaml).
SketchStyles.xaml pełni rolę słownika styli zdefiniowanych w aplikacji.
Sketch.Flow to najważniejszy plik naszego projektu zawierający logikę połączeń pomiędzy screen’ami, zachowania kontrolek, etc.

Resources – w zakładce tej znajdują się pliki xaml z definicjami naszych styli. Tak jak w Silverlight / WPF może to być globalny App.xaml, poszczególna formatka, czy też plik odrębny (tak jak w naszym wypadku SketchStyles.xaml)

Data – zakładka w której możemy stworzyć przykładowe dane wykorzystywane do prezentacji na szkicach. Istnieje kilka opcji kreowania takich danych:
• import z XML,
• tworzenie obiektu na podstawie klasy (w formacie xaml),
• tworzenie obiektu od podstaw.

SketchFlowMap – przedstawia mapę naszych szkiców oraz powiązania istniejące pomiędzy nimi.

Objects and Timeline – struktura kontrolek zamieszczonych na szkicu.

Properties – właściwości zaznaczonego obiektu na szkicu.

SketchFlow Animation – zakładka odpowiedzialna za tworzenie animacji na szkicu.

3) Stworzymy teraz prostą mapę naszej aplikacji. W SketchFlowMap z menu kontekstowego wybieramy Create a screen. Dodawanie kolejnych screenów tworzy nowe obiekty xaml w projekcie.


Zielony trójkącik przy screenie oznacza, który screen jest ustawiony jako startowy.

4) Stwórzmy w takim razie stronę startową naszej aplikacji.



5) Zapewne chcielibyśmy wykorzystać powyższe przyciski, logo i miejsce na konteks na pozostałych stronach. W tym celu zaznaczamy interesujące nas kontrolki i wybieramy z menu kontekstowego Make Into Component Screen (tworzy nam to szablon do wykorzystania na innych szkicach – można go porównać do Master.Page z ASP.NET).
6) W SketchFlowMap pojawił się nam nowy element oznaczony na zielono. Łączymy go z każdym szkicem, na którym chcemy z niego korzystać.



a następnie nanosimy na każdy szkic nową kontrolkę (RepeatedMenu).



Teraz wystarczy tylko poustawiać odpowiednio marginesy i kotwice kontrolki by na każdym szkicu szablon wyglądał identycznie.

7) Kolejną rzeczą jaką się zajmiemy będzie ustawienie nawigacji wykorzystując przyciski na szablonie. By tego dokonać, wchodzimy do kontrolki reprezentującej nasz szablon (RepeatedMenu), zaznaczamy przycisk i z menu kontekstowego wybieramy Navigate To, a następnie wskazujemy interesujący nas szkic.




























8) W tym momencie nasze menu powinno działać poprawnie, odwołując do żądanych przez nas stron.
9) Kolejną funkcjonalnością wartą zbadania jest możliwość tworzenia przykładowych danych pozwalających na zasymulowanie produkcyjnej wersji aplikacji.

W celu stworzenia przykładowych danych przechodzimy do zakładki Data, a następnie wybieramy, Create Sample Data -> New Sample Data. Blend zapyta się nas jak mamy nazwać przykładowe źródło danych i gdzie je przetrzymywać: Projekt, otwarty dokument. Proponują tą pierwszą opcję.






































Jak zauważyliśmy na powyższym rysunku, Blend stworzył źródło danych zawierające kolekcję składającą się z dwóch właściwości. Klikając dwukrotnie możemy zmienić nazwę właściwości. Ikonka po prawej stronie właściwości pozwala na zmianę typu danych. Dodanie MySampleDataSource spowodowało dodanie nowych obiektów do projektu (zawartość katalogu SampleData).

10) Po kilku modyfikacjach MySampleDataSource, klikamy w pierwszą ikonkę przy Collection -> Edit Sample Values. Aplikacja automatycznie generuje przykładowe dane na podstawie typu właściwości oraz jej formatowania.



11) Pozostaje nam już tylko zbindowanie stworzonego źródła danych z kontrolką (w naszym wypadku będzie do ListBox).

Bindowanie ListBox.ItemSource z kolekcją przygotowanych danych.



Bindowanie elementów ListBoxa (ItemTemplate.DataTemplate)



12) Efekt końcowy możemy zaobserwować po naciśnięciu F5



13) Warto zauważyć, że SketchFlow udostępnia nam szereg funkcjonalności pozwalających na nanoszenie notatek bezpośrednio przez klienta lub/i podczas prezentacji. Zakładka MY FEEDBACK zamieszczona na powyższym rysunku posiada narzędzia do zaznaczania oraz pozostawiania krótkich notatek wraz z możliwością eksportu do pliku by w późniejszym etapie przedstawić uwagi projektantowi.



14) W celu odtworzenia zapisanych uwag/notatek od klienta, wybieramy menu Windows -> SketchFlow FeedBack. Pojawia się nowa zakładka do której możemy wczytać uwagi (ikonka + po prawej stronie). Efektem takiego zabiegu jest szkic naszej formatki z wszystkimi uwagami naniesionymi podczas prezentacji.



15) SketchFlow posiada jeszcze jedną przydatną funkcję pozwalającą na łatwe dokumentowanie naszej pracy. Jest to eksport do Microsoft Word.
Wybieramy z menu File – Export to Microsoft Word ...



Mam nadzieję, że po krótce udało mi się przedstawić koncepcję SketchFlow, a powyższy tutorial pozwoli wam zrobić pierwsze kroki z tym interesującym narzędziem.

Dziennik Zdrowej Diety - Wprowadzenie

Rozpoczął się sierpień, a wraz z nim start projektu Dziennik Zdrowej Diety (ang. Diary of Healthy Diet – dla uproszczenia będę go nazywał DHD).
Garść wymagań funkcjonalnych (płynno- muzycznie ;-) ):
System umożliwia każdemu odwiedzającemu na przegląd aktualnych news’ów, przegląd publicznych profili użytkowników za pomocą wyszukiwarki, przegląd zamieszczonych diet oraz możliwość założenia własnego profilu i kontaktu z osobą odpowiedzialną za stronę.
W systemie będą dwa rodzaje użytkowników: administratorzy oraz zwykli użytkownicy.

Rola administratora:
- zarządzanie news’ami,
- zarządzanie zamieszczonymi dietami,
- zarządzanie profilami zwykłych użytkowników.

Rola Zwykłych użytkowników:
- możliwość założenia profilu użytkownika zawierającego kilka sekcji:
- dane kontaktowe na temat użytkownika (awatar, nickname, email, widoczność profilu etc.),
- dane na temat zdrowia (waga, wzrost, karnacja, wiek, płeć),
- dane na temat kondycji użytkownika (rodzaj pracy, aktywności fizyczne, długość snu).
- informacje o stosowanej diecie (nazwa diety, fazy diety, godziny posiłków etc.)
- informacje na temat postępów (wykres BMI, zmiany wagi),
- dziennik.
- możliwość zarządzania własnymi komentarzami,
- możliwość komentowania publicznych profili innych użytkowników,
- możliwość przeglądania zestawienia publicznych profili użytkowników jak również poszczególnych profili.

Czyli z grubsza skupię się na stworzeniu prostego CMS’a, rejestracji użytkowników i przeglądaniu efektów ich pracy nad sobą.
W kolejnej części wykorzystam SketchFlow z aplikacji Microsoft Expression Blend 4 by zaprezentować prototyp tworzonego rozwiązania.

Uwaga: Osoby, które czytają książkę Nick’a Lecrenski’ego „Silverlight 4: Problem - Design – Solution” mogą dostrzec podobieństwo dotyczące projektu jaki sobie wymyśliłem. Zapewniam, że to czysty zbieg okoliczności, choć nie ukrywam faktu, że będę posiłkował się wiedzą zaczerpniętą ze wspomnianej pozycji.