Szukaj na tym blogu

sobota, 30 października 2010

Dziennik Zdrowej Diety – checkpoint i zmiany

Zapewne zauważyliście, że sposób prowadzenia mojego bloga oraz projektu odbiega od założeń postawionych kilka miesięcy temu. Przyznam się szczerze, że pomysł przerósł moje możliwości czasowe co nie oznacza, że się poddaję.

Przez te kilka tygodni starałem się wprowadzić was w sposób tworzenia aplikacji w technologii Silverlight wraz z wykorzystaniem wzorca projektowego MVVM. Ci którzy bawią się Silverlightem na co dzień, stykają się z większością rzeczy tutaj opisanych. Zamierzam nadal dzielić się moją wiedzą, spostrzeżeniami oraz wątpliwościami, jednakże będą to raczej elementy rzemiosła niż opis krok po kroku co dzieje się w projekcie.
Projekt „Dziennik Zdrowej Diety” nabieże także innego charakteru.
Posłuży mi on raczej jako prototyp przy tworzeniu kolejnych aplikacji. Tak więc wszelkiego rodzaju nowinki, eksperymenty będą zaimplementowane dokładnie w nim.
Co chcę osiągnąć ? O tym poniżej.

Założenia:
Aplikacja ma być napisana w Silverlight 4 z wykorzystaniem wzorca MVVM oraz frameworku Prism.
Wsparcie asynchroniczne będzie zrealizowane poprzez framework Async.
We wzorcu MVVM postaram się wykorzystać elementy takich frameworków MVVM jak Caliburn, Calcium, Cinch, MVVM Light itp.
Do komunikacji z bazą danych chcę wykorzystać WCF RIA Services przykryte dodatkową warstwą abstrakcji pozwalającą mi na uniezależnienie się ViewModelu od konkretnych serwisów.

Po co mi to ?
Na początku będzie to WCF RIA Services wraz z Entity Framework 4. Z czasem chcę udostępnić możliwość korzystania z projektu na platformie mobilnej Windows Phone 7, gdzie sposób wymiany danych będzie oparty o protokół OData. Ponieważ interesuje mnie temat chmur obliczeniowych, spróbuję udostępnić możliwość trzymania aplikacji na Windows Azure.
Mam nadzieję, że dużą część aplikacji, dzięki MVVM, będzie wspólna dla każdej z platform.
Do tej pory miałem także znikomą styczność z testami jednostkowymi, tak więc postaram się zgłębić także ten temat opierając się na nUnit.

Co mam ?
Przez ostatnich kilka tygodni rozijałem już swój prototyp, w którym możecie znaleźć:
- architektura oparta o wzorzec MVVM,
- WCF RIA Services jako komunikacja z serwerem,
- Entity Framework 4 pełniący rolę dostępu do danych,
- zaimplementowany wzorzec Repository dla Entity Framework 4,
- elementy frameworka Prism.

Nad czym chcę się skupić w najbliższym czasie ?
- próba implementacji wzorca Repository dla środowiska asynchronicznego,
- wykorzystanie frameworka Async,
- stworzenie warstwy abstrakcji pomiędzy ViewModelem a serwisem,
- autoryzacja i autentykacja w WCF RIA Services

Z niewiadomych przyczyn (wrong Repository UUID) nie udało mi się dorzucić projektu prototypu do istniejącego SVN dla projektu Dziennik Zdrowej Diety dlatego też stworzyłem nowy.
Zinteresowanych zapraszam pod adres: http://devprototype.codeplex.com
Zachęcam do śledzenia moich poczynań :)

środa, 20 października 2010

Przegląd Action (Blend SDK) w kontekście MVVM cz. 2

Trochę czasu minęło od ostatniego postu. Postaram się jednak dotrzymać słowa i dokończyć to co zacząłem ;)

ControlStoryboardAction – Action, który pozwala na uruchomienie StorayBoard czyli animacji w momencie wystąpienia zdarzenia na elemencie źródłowym.

MVVM: Przez pewien czas zastanawiałem się w jaki sposób mogę skorzystać z tego Action w kontekście wzorca MVVM. Rozwiązaniem jest zastosowanie wyzwalacza PropertyChangeTrigger.
Wykorzystując wspomniany wyzwalacz, możemy sprawić by nasza aplikacja uruchomiła się w momencie zmiany właściwości zawartej w naszym ViewModel’u.


SketchFlow - nowy projekt


Tak to wygląda w XAML’u (FirstName jest oczywiście właściwością ViewModel’u).
<Path x:Name="path" Data="…" Stretch="Fill" UseLayoutRounding="False" VerticalAlignment="Bottom">
     <i:Interaction.Triggers>
        <ei:PropertyChangedTrigger Binding="{Binding FirstName}">
            <ei:ControlStoryboardAction Storyboard="{StaticResource SampleStoryboard}"/>
        </ei:PropertyChangedTrigger>
     </i:Interaction.Triggers>
</Path>

GoToStateAction – Action, który zmienia stan wizualny kontrolki w momencie wystąpienia zdarzenia na elemencie źródłowym.

MVVM: Przykładowy scenariusz, czysto hipotetyczny, wygląda tak:
Na naszym widoku posiadamy kontrolkę [elipsa] sygnalizującą dwoma kolorami informację o aktywności zadanego serwisu. Jeśli serwis jest online to kontrolka zmienia stan na wcześniej zdefiniowany „StateOnline”, który nadaje kontrolce kolor zielony. Jeśli serwis jest offline, ustawiany jest stan „StateOffline” zmieniający kolor na czerwony.
W naszym ViewModelu posiadamy właściwość bool IsOnline.
We właściwościach GoToStateAction ustawiamy TriggerType na TimerTrigger. Domyślne ustawienia sprawią, że co 1000 ms będzie sprawdzany stan naszej kontrolki.
Właściwość StateName bindujemy z właściwością IsOnline pamiętając o zastosowaniu konwertera, którego zadaniem będzie zwrócenie stringa „StateOnline” jeśli IsOnline = true oraz „StateOffline” w przeciwnym wypadku.


SketchFlow - nowy projekt


<Ellipse x:Name="ellipse" Height="80" Fill="Black">
    <i:Interaction.Triggers>
        <ei:TimerTrigger>
            <ei:GoToStateAction StateName="{Binding IsOnline, Converter={StaticResource myConverter}}"/>
        </ei:TimerTrigger>
    </i:Interaction.Triggers>
</Ellipse>

HyperlinkAction – Action, który pozwala przekierować użytkownika pod wskazany adres internetowy w momencie wystąpienia zadanego zdarzenia.

MVVM: Jedyne co mi przychodzi do głowy w kontekście tego Action to możliwość odsyłania użytkownika do różnych adresów na podstawie tego co się stanie w ViewModelu. Oczywiście, trzymanie w ViewModelu adresów internetowych nie jest najlepszym rozwiązaniem dlatego też warto byłoby skupić się na trzymaniu jakiegoś enumeryka do którego zbindowana jest właściwość NavigateUriprzy wykorzystaniu konwertera, który tłumaczy daną wartość enumeryka na bardziej odpowiedni adres internetowy. Z racji formy aplikacji, Action ten ma sens tylko dla aplikacji Silverlight’owych.

Dodatkową ciekawostką jest możliwość otworzenia zadanej strony w zadanej ramce:
• _blank - nowe okno/zakładka przeglądarki
• _parent - w oknie rodzica ramki, a jeśli taki nie istnieje to w aktualnym oknie
• _self - w aktualnym oknie


SketchFlow - nowy projekt


<Ellipse x:Name="ellipse" Height="80" RenderTransformOrigin="0.5,0.5" Fill="Black">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <ei:HyperlinkAction NavigateUri="http://devgroup.com.pl" TargetWindow="_blank"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Ellipse>

Na dzisiaj tyle.
Kolejny wpis będzie zawierał Action:
• PlaySoundAction
• RemoveElementAction
• SetDataStoreValueAction
Na sam koniec postaram się także wgłębić w kod i pokazać wam jak Action działa od środka.

sobota, 9 października 2010

Przegląd Action (Blend SDK) w kontekście MVVM cz. 1

Dzisiaj chciałbym opisać akcje (Action) jakie znajdują się w Expression Blend w zakładce Assets -> Behaviors. Wiele z nich ułatwi wam życie pisząc aplikację Silverlight opartą o wzorzec projektowy MVVM.
Dla tych którzy nie posiadają Expression Blend, dostępne jest darmowe BlendSDK, które zawiera wszystkie funkcjonalności opisane poniżej. Link do Blend SDK -> LINK

CallMethodAction – Action, który pozwala na wywołanie dowolnej metody bezparametrowej na wskazanym obiekcie w momencie, gdy wystąpi zdarzenie na obiekcie źródłowym.
Poniżej przykład pokazujący jak wywołać metodę OnAddCommand() z ViewModel’u przy zmianie zaznaczonego elementu na kontrolce dataGrid.

MVVM: zachowanie te może posłużyć do wykonania logiki biznesowej interfejsu graficznego przy wystąpieniu odpowiedniego zdarzenia np. kontrolka DevExpress agDataGrid posiada metodę UnGroup(), która usówa wszystkie grupowania kolumn z grida. Podpinając to zachowanie do przycisku i ustawiając wyzwalacz na zdarzenie Click, możemy w całkiem zgrabny sposób wykorzystać powyższą metodę UnGroup() nie pisząc linijki kodu w CodeBehind naszego widoku.

UWAGA: Nie sugerujcie się możliwością bindowania MethodName ponieważ wskazanie metody spowoduje wystąpienie błędu. W MethodName należy wpisać nazwę metody jaką implementuje obiekt wskazany w TargetObject.


SketchFlow - nowy projekt


<sdk:DataGrid x:Name="dataGrid"
                 ItemsSource="{Binding Customers}"
                 AutoGenerateColumns="False">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged">
      <ei:CallMethodAction TargetObject="{Binding Mode=OneWay}"
                              MethodName="OnAddCommand" />
    </i:EventTrigger>
  </i:Interaction.Triggers>

ChangePropertyAction – Action, który pozwala na zmianę właściwości docelowego elementu w momencie wystąpienia zdarzenia na elemencie źródłowym.

MVVM: Na poniższym przykładzie pokazałem jak zmieniać wartości właściwości SelectedValue zawartej w ViewModel’u. Właściwość ta przechowuje aktualnie zaznaczony wiersz na kontrolce dataGrid.

UWAGA: Przy niektórych kombinacjach (np. Opacity) nie zawierzajcie w 100% Blend’owi i zerknijcie do pliku z XAML’em, ponieważ czasami źle zapisuje ustawione wartości i aplikacja się wywala (zamiast 0.55 ustawił wartość 0,55).


SketchFlow - nowy projekt


<sdk:DataGrid x:Name="dataGrid"
                 ItemsSource="{Binding Customers}"
                 AutoGenerateColumns="False">
  <i:Interaction.Triggers>
    <i:EventTrigger SourceObject="{Binding ElementName=dataGrid}"
                                EventName="SelectionChanged"
                                SourceName="dataGrid">
      <ei:ChangePropertyAction TargetObject="{Binding Mode=OneWay}"
                                  PropertyName="SelectedValue"
                                  TargetName="button"
                                  Value="{Binding SelectedItem,                        ElementName=dataGrid}">
     <ei:ChangePropertyAction.Ease>
      <BackEase EasingMode="EaseInOut"/>
     </ei:ChangePropertyAction.Ease>
      </ei:ChangePropertyAction>
    </i:EventTrigger>
  </i:Interaction.Triggers>

InvokeCommandAction – Action, który pozwala na uruchomienie komenty ICommand dla dowolnej kontrolki i na podstawie dowolnego zdarzenia.

MVVM: Moim zdaniem jest to jedna z najważniejszych Action patrząc pod kątem MVVM. Jak wiemy, Silverlight 4 wprowadził tzw. Commanding do podstaw frameworka (wcześniej można była skorzystać np. z Prism, który rozszerzał kontrolkę Button o możliwość korzystania z tej funkcjonalności). Niestety Commanding jest zaimplementowany tylko dla kontrolki Button (właściwości Commandi CommandParameter). Implementacja dla innych kontrolek oraz innych zdarzeń wymagała napisania odpowiednich Behaviors. InvokeCommandAction robi to z automatu i bez pisania nawet linijki kodu.

Poniższy przykład przedstawia wywołanie metody OnEditCommand(object obj) poprzez EditCommand typu ICommand wraz z przekazaniem do metody aktualnie zaznaczonego wiersza w dataGrid. Metoda jest wywoływana w momencie zaznaczenia wiersza w dataGrid.

Po zabawie z Reflectorem, zauważyłem, że posiadamy dwie opcje dowiązywania do ICommand:
1. Właściwość Command- związujemy się bezpośrednio z właściwością typu ICommand w naszym ViewModel'u,
2. Właściwość CommandName- związuje się do właściwości typu ICommand, wyszukując ją poprzez refleksję w skojarzonej z Action klasie.


SketchFlow - nowy projekt


<sdk:DataGrid x:Name="dataGrid"
                 ItemsSource="{Binding Customers}"
                 AutoGenerateColumns="False">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="SelectionChanged">
      <i:InvokeCommandAction Command="{Binding EditCommand, Mode=OneWay}"
                                           CommandParameter="{Binding SelectedItem, ElementName=dataGrid}" />
    </i:EventTrigger>
  </i:Interaction.Triggers>

W kolejnej części opiszę pozostałe Actions:
• ControlStoryboardAction
• GoToStateAction
• HyperlinkAction
• PlaySoundAction
• RemoveElementAction
• SetDataStoreValueAction

sobota, 2 października 2010

Dziennik Zdrowej Diety - Silverlight i zasoby na serwerze

Jak wiemy, aplikacje Silverlight działają po stronie klienta tak więc całość ściągana jest na komputer użytkownika. Z tego powodu głównym celem jaki nam przyświeca jest stworzenie w taki sposób aplikacji by plik wynikowy XAP był jak najmniejszy w celu wydajnego załadowania programu.

Dziś chciałbym przedstawić sposób dostępu aplikacji Silverlight (klient) do zasobów umieszczonych na serwerze.
Za to zadanie odpowiada klasa WebClient znajdująca się w przestrzeni nazw System.Net

Oto przykład:

private void LoadImageFromServer()
{
    this.wcImg = new WebClient();
    this.wcImg.OpenReadAsync(new Uri("../AppData/picture.jpg"),UriKind.RelativeOrAbsolute));
    this.wcImg.OpenReadCompleted += delegate(object sender, OpenReadCompletedEventArgs e)
    {
         if (e.Error == null)
         {
             using (Stream stream = e.Result)
             {
                 var image = new BitmapImage();
                 image.SetSource(stream);
                 Dispatcher.BeginInvoke(() =>
                 {
                      this.picPhoto.Source = image;
                      this.picPhoto.Width = image.PixelWidth;
                      this.picPhoto.Height = image.PixelHeight;
                 });
             }
         }
    };
    this.wcImg.DownloadProgressChanged += delegate(object sender,DownloadProgressChangedEventArgs e)
    {
         this.txtPercentageLoaded.Text = e.ProgressPercentage + "%";
    };
}

Program pobiera zdjęcie z katalogu AppData zamieszczonego w katalogu wirtualnym aplikacji.

Nic nie zostai na przeszkodzie by zamieścić wszystkie pliki graficzne bezpośrednio w projekcie Silverlight, jednakże należy pamiętać, że postępując w ten sposób, zwiększamy rozmiar naszego pliku XAP czego chcieliśmy uniknąć.

Powyższy sposób pozwala nam na utrzymanie optymalnego rozmiaru pliku XAP co jest równoważne z szybszym ściągnięciem go na maszynę kliencką oraz pozwala nam na swego rodzaju dynamikę tzn. możemy upload'ować pliki na serwer i mieć od razu do nich dostęp z poziomu aplikacji Silverlight.