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ń :)
Szukaj na tym blogu
sobota, 30 października 2010
ś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.

Tak to wygląda w XAML’u (FirstName jest oczywiście właściwością ViewModel’u).
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.

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

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.
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.
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.
<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
<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.
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).
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.
W kolejnej części opiszę pozostałe Actions:
• ControlStoryboardAction
• GoToStateAction
• HyperlinkAction
• PlaySoundAction
• RemoveElementAction
• SetDataStoreValueAction
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.
<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).
<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.
<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:
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.
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.
poniedziałek, 27 września 2010
Licencjonowanie produktów Express Edition
Witam,
Ponieważ nie wszyscy zdają sobie sprawę z możliwości oraz wymagań jakie stawia przed nami firma Microsoft odnośnie korzystania z produktów w wersji Express Edition, postanowiłem zamieścić fragment listu jaki otrzymałem z Centrum Obsługi Klienta Microsoft.
Mam nadzieję, że rozwieje on wszystkie wątpliwości .
Umowa Licencyjna dołączona do narzędzi programistycznych Visual Studio Express Editions daje możliwość komercyjnego wytwarzania aplikacji i ich dystrybucji przy zachowaniu wytycznych zawartych w Umowie Użytkownika Końcowego oprogramowania Microsoft Visual Studio Express.
SQL Server Express można bez dodatkowych opłat redystrybuować, wymagana jest tylko rejestracja na stronie internetowej: http://www.microsoft.com/sql/editions/express/redistregister.mspx
SQL Server Express może być używany wewnątrz firmy komercyjnie, jednakże wykorzystanie komercyjne polegające na hostowaniu SQL Server Express i pobieraniu opłat nie jest możliwe.
Oprogramowanie pozyskane w ramach subskrypcji MSDN AA można wykorzystywać do celów edukacyjnych i badawczych.Nie ma możliwości wykorzystywania oprogramowania z MSDN AA w celach komercyjnych. Informacje na ten temat można znaleźć na stronie: http://www.codeguru.pl/faq.aspx
Wersje testowe oprogramowania służą do zapoznania się z możliwościami i funkcjami oprogramowania. Jeżeli umowa licencyjna nie stanowi inaczej można testować oprogramowanie na sprzęcie, który służy do prowadzenia działalności gospodarczej. Natomiast komercyjne prowadzenie działalności gospodarczej w oparciu o wersje testowe nie jest dopuszczalne, między innymi dlatego, że licencja taka ma ograniczenia czasowe.
Ponieważ nie wszyscy zdają sobie sprawę z możliwości oraz wymagań jakie stawia przed nami firma Microsoft odnośnie korzystania z produktów w wersji Express Edition, postanowiłem zamieścić fragment listu jaki otrzymałem z Centrum Obsługi Klienta Microsoft.
Mam nadzieję, że rozwieje on wszystkie wątpliwości .
Umowa Licencyjna dołączona do narzędzi programistycznych Visual Studio Express Editions daje możliwość komercyjnego wytwarzania aplikacji i ich dystrybucji przy zachowaniu wytycznych zawartych w Umowie Użytkownika Końcowego oprogramowania Microsoft Visual Studio Express.
SQL Server Express można bez dodatkowych opłat redystrybuować, wymagana jest tylko rejestracja na stronie internetowej: http://www.microsoft.com/sql/editions/express/redistregister.mspx
SQL Server Express może być używany wewnątrz firmy komercyjnie, jednakże wykorzystanie komercyjne polegające na hostowaniu SQL Server Express i pobieraniu opłat nie jest możliwe.
Oprogramowanie pozyskane w ramach subskrypcji MSDN AA można wykorzystywać do celów edukacyjnych i badawczych.Nie ma możliwości wykorzystywania oprogramowania z MSDN AA w celach komercyjnych. Informacje na ten temat można znaleźć na stronie: http://www.codeguru.pl/faq.aspx
Wersje testowe oprogramowania służą do zapoznania się z możliwościami i funkcjami oprogramowania. Jeżeli umowa licencyjna nie stanowi inaczej można testować oprogramowanie na sprzęcie, który służy do prowadzenia działalności gospodarczej. Natomiast komercyjne prowadzenie działalności gospodarczej w oparciu o wersje testowe nie jest dopuszczalne, między innymi dlatego, że licencja taka ma ograniczenia czasowe.
WireFrames - szybki sposób na przekazanie wiedzy biznesowej
Dzisiaj zaskoczyła mnie informacja o rezygnacji przez Microsoft z Windows Live Space czyli blogów z pod znaczka MS. Z tego względu postanowiłem zajrzeć co się znajduje na moim starym i zapomnianym blogu. Efektem tego przeglądu jest przeklejenie kilku wpisów.
Ostatnio pracuję razem z kumplami nad rozwojem aplikacji typu ERP.
Ponieważ tak się zdarzyło, że z naszej czwórki tylko ja i kolega Tomek posiadaliśmy największą wiedzę biznesową apropo naszego rozwiązania, padł pomysł by stworzyć diagramy przypadków użycia wraz z opisami, które miały być czymś co pozwoli całej grupie na zaznajomienie się z tematem.
Szybko jednak okazało się, że każdy z nas ma własny sposób tworzenia przypadków użycia co spowodowało wiele niejasności.
Kolega Przemek zaproponował WireFrames.
WireFrames to obraz formatek aplikacji wraz z opisem funkcjonalności pozwalający na szybkie zapoznanie się z zadanym tematem. Ponieważ w naszym przypadku WireFrames tworzone jest przy pomocy PowerPoint, w każdej chwili można dodać/usunąć/przestawić odpowiedni element na slajdzie formatki.
Dodatkowo PowerPoint udostępnia szereg funkcjonalności typu hiperlinki, animacje przez co można stworzyć w bardzo szybki sposób szkielet aplikacji (warstwa prezentacji) wraz ze wszystkimi przejściami pomiędzy oknami.
Bardzo fajnie sprawdza się to w grupie ponieważ wymusza na projektantach spójny styl tworzenia danej partii projektu.
Po kilku spotkaniach i omówieniu naszej pracy bardzo szybko doszliśmy do wspólnych wniosków dzięki czemu możemy wkroczyć w kolejny etap procesu tworzenia naszej aplikacji - Domain Model..
Poniżej przykładowy screen WireFrames.
Ten sposób podejścia do tworzenia UI może być alternatywą do SketchFlow.
Efekt końcowy jest podobny czyli możliwość pokazania klientowi interfejsu użytkownika aplikacji wraz z przejściami oraz możliwością wprowadzenia wszystkich poprawek na bieżąco na długo przed rozpoczęciem developmentu.
Ostatnio pracuję razem z kumplami nad rozwojem aplikacji typu ERP.
Ponieważ tak się zdarzyło, że z naszej czwórki tylko ja i kolega Tomek posiadaliśmy największą wiedzę biznesową apropo naszego rozwiązania, padł pomysł by stworzyć diagramy przypadków użycia wraz z opisami, które miały być czymś co pozwoli całej grupie na zaznajomienie się z tematem.
Szybko jednak okazało się, że każdy z nas ma własny sposób tworzenia przypadków użycia co spowodowało wiele niejasności.
Kolega Przemek zaproponował WireFrames.
WireFrames to obraz formatek aplikacji wraz z opisem funkcjonalności pozwalający na szybkie zapoznanie się z zadanym tematem. Ponieważ w naszym przypadku WireFrames tworzone jest przy pomocy PowerPoint, w każdej chwili można dodać/usunąć/przestawić odpowiedni element na slajdzie formatki.
Dodatkowo PowerPoint udostępnia szereg funkcjonalności typu hiperlinki, animacje przez co można stworzyć w bardzo szybki sposób szkielet aplikacji (warstwa prezentacji) wraz ze wszystkimi przejściami pomiędzy oknami.
Bardzo fajnie sprawdza się to w grupie ponieważ wymusza na projektantach spójny styl tworzenia danej partii projektu.
Po kilku spotkaniach i omówieniu naszej pracy bardzo szybko doszliśmy do wspólnych wniosków dzięki czemu możemy wkroczyć w kolejny etap procesu tworzenia naszej aplikacji - Domain Model..
Poniżej przykładowy screen WireFrames.
Ten sposób podejścia do tworzenia UI może być alternatywą do SketchFlow.
Efekt końcowy jest podobny czyli możliwość pokazania klientowi interfejsu użytkownika aplikacji wraz z przejściami oraz możliwością wprowadzenia wszystkich poprawek na bieżąco na długo przed rozpoczęciem developmentu.
środa, 22 września 2010
Sekwencja wywołań w asynchronicznym środowisku Silverlight cz. 2 - CoRutines
W dzisiejszej części przedstawię sposób wykorzystania corutines w Silverlight.
Corutines to mechanizm pozwalający na wykonywanie sekwencji kodu tzn. do puki nie skończy się działanie danego bloku kodu, program nie przejdzie dalej. W Silverlight, gdzie wszystko musi być wywoływane asynchronicznie tego typu mechanizm jest wręcz zbawieniem. Nie oznacza to, że od teraz wszelkiego rodzaju operacje będziesz wykonywał przy wykorzystaniu corutines. To by zabiło całą koncepcję technologii Silverlight, jednakże zdarzają się sytuacje gdzie do wykonania pewnego bloku kodu potrzebujesz dane będące wynikiem operacji poprzedzającego bloku kodu.
Domyślnie język C# nie wspiera corutines. Mechanizm ten można natomiast zbudować z elementów jakie dostarcza nam .NET.
Na rozwiązanie, które chcę zaproponować składa się:
- klasa wątków BackgroundWorker,
- interfejs IEnumerable,
- słówko yield.
Ponieważ większość z nas zetknęła się ze słówkiem yield na samym początku przygody z językiem C# (zapewne czytając jakieś opasłe tomisko) po czym przez resztę swojego komercyjnego / niekomercyjnego doświadczenia nie miała sposobności wykorzystać go (tak, generalizuję), postaram się na prostym przykładzie pokazać jego działanie.
Wyobraźmy sobie, że iterujemy pętlą foreach po tablicy string’ów { „A”, „B”, „C” }. Czyli każda kolejna iteracja bieże kolejny element tablicy. Dla przedstawionego poniżej przykładu tablica string’ów jest równoważna YieldTab() :
Analizując przykład pierwszy bardzo łatwo wychwycić różnicę. Przy kolejnej iteracji po IEnumerable , program wykonuje wszystko co się znajduje pomiędzy słówkami yield oraz zwraca wartość elementu.
Myślę, że koncepcja działania jest mniej więcej zrozumiała.
Zważając na powyższy przykład opiszę słowno muzycznie jak dziła mechanizm corutines.
1. Tworzymy interfejs pomocniczy IResult
Zadaniem metody Execute() będzie wywołanie dowolnej metody przekazanej to mechanizmu Corutines, natomiast zdarzenie Completed będzie informowało o zakończeniu działania przekazanej metody.
2. Tworzymy klasę implementującą powyższy mechanizm zintegrowany z klasą BackgroundResult
Klasa ta w konstruktorze przyjmuje Action będący delegatem, który nie przyjmuje żadnych parametrów i nie zwraca, żadnej wartości. W skrócie, w konstruktorze przekazujemy referencję do metody odpowiadającej wymaganiom powyższego delegata.
Metoda Execute() uruchamia przekazaną metodę w trybie asynchronicznym i nasłuchuje moment jej zakończenia poprzez zdarzenie RunWorkerCompleted, który następnie wzbudza zdarzenie Completed.
3. Tworzymy klasę, której zadaniem będzie iteracja po IEnumerable w sposób jaki jest właściwy dla opisywanego mechanizmu Corutines.
Klasa przyjmuje w konstruktorze kolekcję elementów implementujących interfejs IResult, a następnie pobiera enumerator tej kolekcji.
MoveNext() enumeratora można przyrównać do pojedyńczego odczytania z pętli np. foreach, gdzie wskazany element znajduje się we właściwości Current. Kolejne wywołanie metody MoveNext() powoduje przesunięcie obecnego elementu o jeden dalej.
Wywołując metodę Enumerate() uruchamiamy swoistą funkcję rekurencyjną ChildCompleted(object sender, EventArgs args), gdzie zakończone zadanie wywołuje ponownie tą samą funkcję.
Proces kończy się w momencie osiągnięcia kresu przekazanej kolekcji.
A tak to działa w praktyce:
Gdzie mój serwis ma postać:
Ponieważ zapytania do webserwisu są również asynchroniczne, skorzystałem z klasy AutoResetEvent, która potrafi zastopować aktualny wątek (metoda WaitOne())aż do momentu uruchomienia metody Set(), która go wzbudza.
Wywołanie postaci Dispatcher.BeginInvoke(Action a) pozwala na wykonanie kodu w wątku głównym UI aplikacji Silverlight.
Źródła do przykładu znajdują się pod tym adresem: http://dhd.codeplex.com/releases/view/52747
Na zakończenie chciałbym wspomnieć, że powyższe rozwiązanie nie jest mojego autorstwa tylko Pana Roba Eisenberga, który jest twórcą frameworka MVVM Caliburn (http://caliburn.codeplex.com/).
Corutines to mechanizm pozwalający na wykonywanie sekwencji kodu tzn. do puki nie skończy się działanie danego bloku kodu, program nie przejdzie dalej. W Silverlight, gdzie wszystko musi być wywoływane asynchronicznie tego typu mechanizm jest wręcz zbawieniem. Nie oznacza to, że od teraz wszelkiego rodzaju operacje będziesz wykonywał przy wykorzystaniu corutines. To by zabiło całą koncepcję technologii Silverlight, jednakże zdarzają się sytuacje gdzie do wykonania pewnego bloku kodu potrzebujesz dane będące wynikiem operacji poprzedzającego bloku kodu.
Domyślnie język C# nie wspiera corutines. Mechanizm ten można natomiast zbudować z elementów jakie dostarcza nam .NET.
Na rozwiązanie, które chcę zaproponować składa się:
- klasa wątków BackgroundWorker,
- interfejs IEnumerable
- słówko yield.
Ponieważ większość z nas zetknęła się ze słówkiem yield na samym początku przygody z językiem C# (zapewne czytając jakieś opasłe tomisko) po czym przez resztę swojego komercyjnego / niekomercyjnego doświadczenia nie miała sposobności wykorzystać go (tak, generalizuję), postaram się na prostym przykładzie pokazać jego działanie.
class Program
{
static void Main(string[] args)
{
foreach(var msg in Teksty())
{
Console.WriteLine(msg);
}
Console.ReadKey();
}
public static IEnumerable<string> Teksty()
{
yield return "Start";
Console.WriteLine("Tutaj sobie coś wykonuję");
Console.ReadKey();
yield return "Drugi krok";
Console.WriteLine("Kolejne czynności");
Console.ReadKey();
yield return "Zakończenie";
}
}
Wyobraźmy sobie, że iterujemy pętlą foreach po tablicy string’ów { „A”, „B”, „C” }. Czyli każda kolejna iteracja bieże kolejny element tablicy. Dla przedstawionego poniżej przykładu tablica string’ów jest równoważna YieldTab() :
class Program
{
static void Main(string[] args)
{
string[] normalTab = {"A", "B", "C"};
foreach(var msg in normalTab)
{
Console.WriteLine(msg);
}
Console.ReadKey();
foreach (var msg in YieldTab())
{
Console.WriteLine(msg);
}
Console.ReadKey();
}
public static IEnumerable YieldTab()
{
yield return "A";
yield return "B";
yield return "C";
}
}
Analizując przykład pierwszy bardzo łatwo wychwycić różnicę. Przy kolejnej iteracji po IEnumerable
Myślę, że koncepcja działania jest mniej więcej zrozumiała.
Zważając na powyższy przykład opiszę słowno muzycznie jak dziła mechanizm corutines.
1. Tworzymy interfejs pomocniczy IResult
public interface IResult
{
void Execute();
event EventHandler Completed;
}
Zadaniem metody Execute() będzie wywołanie dowolnej metody przekazanej to mechanizmu Corutines, natomiast zdarzenie Completed będzie informowało o zakończeniu działania przekazanej metody.
2. Tworzymy klasę implementującą powyższy mechanizm zintegrowany z klasą BackgroundResult
public class BackgroundResult : IResult
{
private readonly Action action;
public BackgroundResult(Action action)
{
this.action = action;
}
public void Execute()
{
var backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += (e, sender) => action();
backgroundWorker.RunWorkerCompleted += (e, sender) => Completed(this, EventArgs.Empty);
backgroundWorker.RunWorkerAsync();
}
public event EventHandler Completed;
}
Klasa ta w konstruktorze przyjmuje Action będący delegatem, który nie przyjmuje żadnych parametrów i nie zwraca, żadnej wartości. W skrócie, w konstruktorze przekazujemy referencję do metody odpowiadającej wymaganiom powyższego delegata.
Metoda Execute() uruchamia przekazaną metodę w trybie asynchronicznym i nasłuchuje moment jej zakończenia poprzez zdarzenie RunWorkerCompleted, który następnie wzbudza zdarzenie Completed.
3. Tworzymy klasę, której zadaniem będzie iteracja po IEnumerable
public class ResultEnumerator
{
private readonly IEnumerator _enumerator;
public ResultEnumerator(IEnumerable children)
{
_enumerator = children.GetEnumerator();
}
public void Enumerate()
{
ChildCompleted(null, EventArgs.Empty);
}
private void ChildCompleted(object sender, EventArgs args)
{
var previous = sender as IResult;
if (previous != null)
previous.Completed -= ChildCompleted;
if (!_enumerator.MoveNext())
return;
var next = _enumerator.Current;
next.Completed += ChildCompleted;
next.Execute();
}
}
Klasa przyjmuje w konstruktorze kolekcję elementów implementujących interfejs IResult, a następnie pobiera enumerator tej kolekcji.
MoveNext() enumeratora można przyrównać do pojedyńczego odczytania z pętli np. foreach, gdzie wskazany element znajduje się we właściwości Current. Kolejne wywołanie metody MoveNext() powoduje przesunięcie obecnego elementu o jeden dalej.
Wywołując metodę Enumerate() uruchamiamy swoistą funkcję rekurencyjną ChildCompleted(object sender, EventArgs args), gdzie zakończone zadanie wywołuje ponownie tą samą funkcję.
Proces kończy się w momencie osiągnięcia kresu przekazanej kolekcji.
A tak to działa w praktyce:
public partial class MainPage : UserControl
{
private AutoResetEvent trigger = new AutoResetEvent(false);
public MainPage()
{
InitializeComponent();
this.Loaded += MainPage_Loaded;
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var enumerator = new ResultEnumerator(CallWebServiceMethods());
enumerator.Enumerate();
}
public IEnumerable CallWebServiceMethods()
{
yield return new BackgroundResult(() =>
{
var serwis = new LocalSerwis.Service1SoapClient();
serwis.MetodaPierwszaCompleted += (sender, e) =>
{
Dispatcher.BeginInvoke(() => MessageBox.Show(e.Result));
trigger.Set();
};
serwis.MetodaPierwszaAsync();
trigger.WaitOne();
});
yield return new BackgroundResult(() =>
{
var serwis = new LocalSerwis.Service1SoapClient();
serwis.MetodaDrugaCompleted += (sender, e) =>
{
Dispatcher.BeginInvoke(() => MessageBox.Show(e.Result));
trigger.Set();
};
serwis.MetodaDrugaAsync("Ala ma kota");
trigger.WaitOne();
});
}
}
Gdzie mój serwis ma postać:
public class Service1 : System.Web.Services.WebService
{
[WebMethod]
public string MetodaPierwsza()
{
return "Wynik Metody Pierwszej";
}
[WebMethod]
public string MetodaDruga(string msg)
{
char[] chars = msg.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
}
Ponieważ zapytania do webserwisu są również asynchroniczne, skorzystałem z klasy AutoResetEvent, która potrafi zastopować aktualny wątek (metoda WaitOne())aż do momentu uruchomienia metody Set(), która go wzbudza.
Wywołanie postaci Dispatcher.BeginInvoke(Action a) pozwala na wykonanie kodu w wątku głównym UI aplikacji Silverlight.
Źródła do przykładu znajdują się pod tym adresem: http://dhd.codeplex.com/releases/view/52747
Na zakończenie chciałbym wspomnieć, że powyższe rozwiązanie nie jest mojego autorstwa tylko Pana Roba Eisenberga, który jest twórcą frameworka MVVM Caliburn (http://caliburn.codeplex.com/).
Subskrybuj:
Posty (Atom)