By zrobić show z Blenda 4 można zawsze na pierwszy ogień rzucić kontrolkę PathListBox, dynamiczny layout, efekty przejść, warunkowe zachowania… Rzeczy związane z codziennym pisaniem aplikacji, różnymi problemami w designie nie wydają się już tak ciekawe… A tymczasem niesłusznie, bo … są to sprawy, które dotyczą … prawie każdego programisty, który ma współpracować z grafikiem lub … jeśli sam pełni podwójną rolę, chce zyskać na czasie i na wygodzie.
Zacznijmy od wzorców projektowych, a konkretne od MVVM, który stał się wręcz standardem w przypadku aplikacji w Silverlight i WPF. W nowym Blend poczyniono różne udogodnienia w tym kierunku.
Jeśli chodzi o predefiniowane szablony, to dostajemy nowy rodzaj projektu WPF/Silverlight Databound Application. Dostajemy stworzony na wstępie szkielet view modelu, widok, przykładowe dane, wywołanie metody… View modele nie zakładają konkretnej platformy do ich budowania. Jak dla mnie bardziej przydatnym na co dzień i w pełni wystarczającym jest szablon elementu UserControl with ViewModel. Za jego pomocą tworzymy, to co w wyżej wymienionym szablonie projektu jest predefiniowane na przykładzie, czyli szkielet view modelu i związany z nim widok. Aplikacja nie musi być koniecznie rodzaju DataBound Application.
Wzorzec MVVM zakłada wywoływanie logiki poprzez bindowanie komend w widoku. W Silverlight 4 tylko Button, HyperlinkButton i MenuItem w menu kontekstowym przewidują komendę jako swoją propercję do zbindowania. A co z innymi zdarzeniami? A co z innymi kontrolkami i obiektami wizualnymi? A co jak programista nie miał specjalnej ochoty pisać komend i część funkcjonalności mamy tylko w postaci metod? W Blendzie 4 wystarczy… zrobić drag & drop obiektu komendy lub metody z panelu Data na obszar roboczy.
Bardzo szybko i prosto się to robi, ale … nie ma w tym żadnej magii. Jeśli sprawa nie dotyczy odpowiedniej kontrolki i komendy, to designer zamiast bindingu do komendy wstawia nam akcję wywołania komendy lub metody wyzwalaną triggerem na typowym dla danego obiektu zdarzeniu (które - podobnie jak i cały trigger - możemy szybko zmienić na inny rodzaj). Każdy to sobie może sam oczywiście zrobić, ale od tego mamy właśnie narzędzia, by ten proces sobie maksymalnie skrócić …
Przykładowe dane - kolejne zagadnienie, które pojawi się na pewno na styku programista-designer. Grafik potrzebuje przykładowych danych, aby zobaczyć jak będzie wyglądać całościowo UI, bez tego nie widzi w pełni swojego końcowego dzieła zanim nie uruchomi aplikacji, a to jest dość uciążliwe. Przykładowe dane możemy łatwo tworzyć od Blenda 3, ale w typowym scenariuszu nie jest to najwygodniejsze… Dlaczego? Bo zazwyczaj mając napisaną przez kogoś aplikację nie potrzebujemy definiować już struktur, a raczej wykorzystać już istniejące, ale z przykładowymi, niekoniecznie nawet poprawnymi biznesowo wartościami. Po drugie programiści często skupiają się wyłącznie na pisaniu kodu i nie przykładają wagi do tego, aby tworzone przez nich struktury danych i view modele były przyjazne grafikowi w czasie designu.
Możemy tym wszystkim … nie martwić się, jeśli używamy nowego Blenda. Została dodana opcja tworzenia przykładowych danych na podstawie danej klasy. Co więcej propercje nie muszą mieć setterów, a klasy publicznych konstruktorów, … Programiści nie muszą myśleć o przyjazności dla designu, wszelkie braki wyrównuje narzędzie. Generowany jest xaml z instancjami obiektów odpowiadających naszym strukturom danych wypełnionych przykładowymi wartościami, które możemy też edytować. Dla bindingu w czasie designu jest to w pełni wystarczające.
Jeśli korzystając z powyższej metody utworzyliśmy sobie instancję naszego view modelu, to możemy przeciągnąć ją na korzeń danego widoku. Utworzy się d:DataContext, czyli DataContext obowiązujący tylko na okres designu. Jest to wygodne, bo jest w pełni transparentne dla działania aplikacji w runtime.
Jeden ruch i widzimy wszystkie potrzebne dane w czasie designu.
Kolejne zagadnienie - resourcy dostępne tylko w czasie designu. Pewnie wielu bez entuzjazmu powie, że nie widzi zastosowania czegoś takiego u siebie w codziennej pracy. Nic bardziej mylnego! Ileż to razy piszemy złożone aplikacje, w których pewne dane są doczytywane w czasie runtimu z innych modułów. MEF i wszelkiej maści kontenery są nieocenione, jeśli chodzi o elastyczność i luźne powiązanie architektury. Jednak to co jest powodem to zadowolenia programisty, nie musi być już powodem zadowolenia dla grafika. Grafik zacznie tutaj przeklinać, jeśli okaże się, że słownik ze skórką aplikacji jest doczytywany w kodzie w runtimie (który nie jest analizowany) i nie widać go w czasie designu, a Blend sypie wyjątkami i ostrzeżeniami.
Co zrobić? Zawsze można pogonić programistę, by nam takich przekombinowań nie robił, ale używając nowego Blenda możemy sprawić, że wilk będzie syty i owca cała. Wystarczy, abyśmy załączyli sam słownik ze skórką jako element projektu. Blend po wykryciu nie rozwiązanych odniesień do zasobów i widząc słowniki w projekcie, sam … wyświetli okienko dialogowe, czy nie chcielibyśmy widzieć, któregoś z dostępnych słowników na czas designu. Wtedy dołączy wybrany przez nas słownik do specjalnego słownika DesignTimeResources.xaml trzymanego w katalogu Properties. Tu chciałbym jeszcze raz podkreślić, że cały zabieg nie wpływa w żaden sposób na działającą w runtime aplikację, jest to tylko udogodnienie na czas designu.
Jakieś przykłady z życia wzięte? Ze swojej autobiografii mogę wspomnieć problem jaki wiązał się z pobieraniem z weba skórek i ładowanie ich w czasie runtime do aplikacji. W ówczesnych czasach kończyło się na ingerencji w App.xaml i kopiowaniem skórki do projektu. Dziś też ją byśmy ją skopiowali (nie ma wszak cudów, by pracować na skórce bez jej importu), ale byłoby to zrobione doskonalej. Mało tego, podmieniając załączone słowniki w słowniku dla designu możemy w designie podmieniać różne skórki bez ingerencji w działanie aplikacji. Inny przykład to sytuacja właśnie z MEF, gdy po jego zastosowaniu definicja słownika z App.xaml została zamieniona na dodawanie słownika w kodzie. Tej funkcjonalności użyłem jako jednej z pierwszych w Blend 4, co zostało wymuszone przez zaistniałą sytuację.
A oto moja prosta aplikacyjka w pełnej krasie, w której użyłem opisane wszystkie w tym poście nowe funkcjonalności Blenda. Jak widać dane w runtime różnią się nieco od danych pokazywanych w designerze. Przyciski natomiast wyglądają tak samo dzięki słownikowi dodanemu na czas designu.
Źródła prezentowanego przykładu, jak i opis powyższych zagadnień w nieco innej postaci zostały opublikowane tutaj.