Silverlight 4 w działaniu Silverlight 4, MVVM i usługi WCF RIA Services Pete Brown przełożył Jakub Niedźwiedź APN Promise Warszawa 2011
Silverlight 4 w działaniu. Silverlight 4, MVVM i usługi WCF RIA Services Tytuł oryginału: Silverlight 4 in action. Silverlight 4, MVVM, and WCF RIA Services, by Pete Brown Original edition copyright 2010 by Manning Publications, Co. All rights reserved. Polish edition copyright 2011 APN PROMISE SA. All rights reserved. APN PROMISE SA, ul. Kryniczna 2, 03-934 Warszawa tel. +48 22 35 51 600, fax +48 22 35 51 699 e-mail: mspress@promise.pl Wszystkie prawa zastrzeżone. Żadna część niniejszej książki nie może być powielana ani rozpowszechniana w jakiejkolwiek formie i w jakikolwiek sposób (elektroniczny, mechaniczny), włącznie z fotokopiowaniem, nagrywaniem na taśmy lub przy użyciu innych systemów bez pisemnej zgody wydawcy. Microsoft oraz znaki towarowe wymienione na stronie http://www.microsoft.com/about/ legal/en/us/intellectualproperty/trademarks/en-us.aspx są zarejestrowanymi znakami towarowymi grupy Microsoft. Wszystkie inne nazwy handlowe i towarowe występujące w niniejszej publikacji mogą być znakami towarowymi zastrzeżonymi lub nazwami zastrzeżonymi odpowiednich firm odnośnych właścicieli. Przykłady firm, produktów, osób i wydarzeń opisane w niniejszej książce są fikcyjne i nie odnoszą się do żadnych konkretnych firm, produktów, osób i wydarzeń. Ewentualne podobieństwo do jakiejkolwiek rzeczywistej firmy, organizacji, produktu, nazwy domeny, adresu poczty elektronicznej, logo, osoby, miejsca lub zdarzenia jest przypadkowe i niezamierzone. APN PROMISE SA dołożyła wszelkich starań, aby zapewnić najwyższą jakość tej publikacji. Jednakże nikomu nie udziela się rękojmi ani gwarancji. APN PROMISE SA nie jest w żadnym wypadku odpowiedzialna za jakiekolwiek szkody będące następstwem korzystania z informacji zawartych w niniejszej publikacji, nawet jeśli APN PROMISE została powiadomiona o możliwości wystąpienia szkód. ISBN: 978-83-7541-070-9 Przekład: Jakub Niedźwiedź Redakcja: Marek Włodarz Korekta: Ewa Swędrowska Skład i łamanie: MAWart Marek Włodarz
Spis treści Wstęp xix Podziękowania xxi Informacje na temat tej książki O ilustracji na okładce xxix Część 1 Wprowadzenie do Silverlight...................1 xxiii 1. Wprowadzenie do Silverlight 1 1.1. Silverlight i sieć WWW 3 1.2. Silverlight i WPF 4 1.3. Typy aplikacji Silverlight 5 1.4. Co nowego pojawiło się od pierwszego wydania 6 Funkcje dla aplikacji biznesowych i klienckich 6 Usprawnienia multimediów i grafiki 7 Interakcja z użytkownikiem 8 Tekst 8 1.5. Rozpoczęcie programowania w Silverlight 9 Instalowanie środowiska programistycznego 9 Przydatne witryny 10 1.6. Budowa pierwszej aplikacji internetowej w Silverlight 10 Przygotowanie projektu 11 Interfejs użytkownika 13 Wywoływanie wyszukiwania w serwisie Twitter 14 Przetwarzanie wyników i wiązanie z kontrolką ListBox 15 Poprawianie zawartości kontrolki ListBox 19 1.7. Podsumowanie 20 2. Fundamenty XAML 23 2.1. Podstawy XAML 24 Obiekty 25 Przestrzenie nazw 26 Właściwości 29 Właściwości zależnościowe 31 Właściwości połączone 33 Zdarzenia 35 Polecenia 36 Zachowania 38 2.2. Drzewa obiektów i zakres nazw 39 Drzewa obiektów 39 Zakres nazw 42 2.3. Rozszerzenia XAML i konwertery typów 44 Rozszerzenia kodu znacznikowego 44 Konwertery typów 45 2.4. Ładowanie XAML podczas działania programu 48 2.5. Narzędzia do pracy z XAML 51 2.6. Podsumowanie 52
iv Spis treści 3. Model aplikacji i wtyczka Silverlight 53 3.1. Model aplikacji Silverlight 54 Proces rozruchowy aplikacji 54 XAP 56 Plik manifestu aplikacji 57 Obiekt aplikacji Silverlight 58 Zależności aplikacji 62 Przechowywanie podzespołów w pamięci podręcznej 62 3.2. Tworzenie wtyczki Silverlight 65 Wykorzystanie znacznika object 67 Wykorzystanie pliku narzędziowego Silverlight.js 68 Tworzenie wystąpienia wtyczki Silverlight 69 3.3. Integrowanie wtyczki Silverlight 70 Wiązanie aplikacji Silverlight z modelem DOM strony HTML 71 Określanie początkowego wyglądu aplikacji 72 Obsługa zdarzeń wtyczki 77 Przesyłanie parametrów inicjujących 80 3.4. Podsumowanie 81 4. Integracja z przeglądarką 82 4.1. Silverlight i model DOM w HTML 83 4.2. Zarządzanie stroną WWW z poziomu kodu zarządzanego 85 Nawigowanie po zawartości strony WWW 85 Praca z właściwościami elementów 87 Obsługa informacji o stylach CSS 87 Dostęp do łańcucha zapytania 88 4.3. Praca z oknem przeglądarki użytkownika 89 Komunikaty dla użytkownika 89 Nawigowanie w oknie przeglądarki 91 Odkrywanie właściwości przeglądarki 91 4.4. Łączenie świata skryptowego i świata kodu zarządzanego 92 Wywoływanie kodu zarządzanego z poziomu JavaScript 93 Korzystanie z języka JavaScript z poziomu kodu zarządzanego 95 4.5. Umieszczanie HTML w Silverlight 96 Wstawianie kontrolki WebBrowser 97 Korzystanie z WebBrowserBrush 103 4.6. Podsumowanie 106 5. Integracja z pulpitem 107 5.1. Silverlight poza przeglądarką 108 Możliwości i ograniczenia 110 Doświadczenie użytkownika końcowego 111 5.2. Tworzenie aplikacji uruchamianych poza przeglądarką 113 Plik ustawień trybu uruchamiania poza przeglądarką 113 Kontrola sposobu instalacji 115 Dostosowywanie ikon 118 Sprawdzanie stanu sieci 120 Ostrzeganie użytkownika przy pomocy powiadomień 121 Szczegóły implementacyjne 123
Spis treści v 5.3. Ucieczka z piaskownicy podwyższone zaufanie 123 Tworzenie aplikacji z podwyższonym zaufaniem 124 Wykrywanie trybu podwyższonego zaufania 127 5.4. Dostęp do plików lokalnych 128 Dostęp do folderów specjalnych 128 Odczytywanie danych z pliku 129 Zapisywanie do pliku 129 5.5. Automatyzacja COM 130 Wykrywanie dostępności automatyzacji COM 130 Wykorzystanie automatyzacji COM do komunikacji głosowej w Silverlight 132 Dostęp do danych GPS przy użyciu automatyzacji COM 132 Automatyzacja programu Excel 133 5.6. Kontrola okna gospodarza 135 Podstawowe właściwości okna 136 Zmienianie otoczki okna 137 Minimalizowanie, maksymalizowanie, przywracanie rozmiaru i zamykanie okna 138 Przenoszenie okna 139 Zmienianie rozmiaru okna 140 5.7. Uruchamianie na pełnym ekranie 142 Normalny tryb pełnoekranowy 142 Tryb pełnoekranowy z podwyższonym zaufaniem 144 5.8. Przechowywanie danych w pamięci izolowanej 145 IsolatedStorageFile: wirtualny system plików 145 Odczytywanie i zapisywanie plików w pamięci izolowanej 150 Administrowanie pamięcią izolowaną 153 5.9. Podsumowanie 153 6. Obrazowanie, układ elementów i transformacje 155 6.1. UIElement i FrameworkElement 156 Właściwości 156 Metody 163 6.2. Proces obrazowania 165 Tyknięcie zegara 166 Funkcja zwrotna wywoływana dla obrazowania każdej klatki 167 Rasteryzacja 168 6.3. System układu elementów 174 Układ wieloprzebiegowy mierzenie i ustawianie 175 Klasa LayoutInformation 177 Uwarunkowania wydajności 178 6.4. Transformacje obrazowania 179 RotateTransform 180 ScaleTransform 181 SkewTransform 181 TranslateTransform 182 TransformGroup 182 CompositeTransform 183 MatrixTransform 184 6.5. Transformacje rzutowania trójwymiarowego 187 PlaneProjection 187 Matrix3dProjection 189 6.6. Podsumowanie 191
vi Spis treści 7. Panele 192 7.1. Canvas 193 Organizowanie zawartości panelu Canvas 193 7.2. StackPanel 197 7.3. Grid 199 Ustawianie zawartości panelu Grid 200 Rozmieszczanie zawartości panelu Grid 202 Zajmowanie wielu komórek 202 Określanie rozmiaru 203 Programowa praca z panelem Grid 206 Dostosowywanie obramowania komórki 207 7.4. Podsumowanie 210 8. Dane wejściowe od użytkownika 211 8.1. Przechwytywanie klawiatury 212 Zrozumienie fokusu 212 Obsługa zdarzeń klawiatury 213 Obsługa klawiszy modyfikujących 215 8.2. Dane wejściowe myszy 216 Zdarzenia przycisków i ruchu myszy 217 Korzystanie z kółka myszy 218 8.3. Korzystanie z wielodotyku 221 8.4. Zbieranie danych wprowadzanych wirtualnym atramentem 223 Tworzenie obiektu InkPresenter 223 Zbieranie informacji o atramencie 224 Nadawanie stylu atramentowi 226 8.5. Podsumowanie 227 9. Tekst 228 9.1. System tekstowy 229 Obrazowanie z dokładnością do części piksela 230 Wskazówki dla tekstu 230 9.2. Wyświetlanie tekstu 232 Właściwości czcionki 233 Kontrola przepływu tekstu 236 Właściwości tekstu 237 Odstępy 240 9.3. Osadzanie czcionek 243 9.4. Wprowadzanie i edycja tekstu 244 Obsługa podstawowego wejścia tekstowego 245 Zrozumienie edytorów metod wejściowych 247 Kopiowanie tekstu przy pomocy interfejsu API dla schowka 250 Zbieranie poufnych danych 251 9.5. Wprowadzanie i wyświetlanie tekstu sformatowanego 252 Formatowanie i elementy wewnętrzne 253 Praca z zaznaczonym tekstem 258 9.6. Podsumowanie 261
Spis treści vii 10. Kontrolki podstawowe i kontrolki użytkownika 263 10.1. Control 264 Wygląd 264 Nawigacja i stan 265 Szablony 266 10.2. ContentControl 267 ContentPresenter 269 10.3. Kontrolki przycisków 270 Button 270 HyperlinkButton 271 RadioButton 272 CheckBox 274 10.4. ItemsControl 275 ListBox 276 ComboBox 279 TabControl 279 10.5. Tworzenie kontrolek UserControl 282 Definiowanie wyglądu 284 Definiowanie zachowania 285 Wywoływanie kontrolki 288 10.6. Podsumowanie 289 Część 2 Struktura aplikacji...........................291 11. Wiązanie 293 11.1. Wiązanie z naszymi danymi 294 Opanowanie składni wiązania 295 Wybieranie trybu wiązania 297 11.2. Zrozumienie źródła wiązania 299 Wiązanie z właściwością 300 Wiązanie z obiektem 301 Wiązanie z elementem interfejsu użytkownika 303 Wiązanie z elementem indeksowanym 306 Wiązanie do elementu z kluczem tekstowym 307 Wiązanie z całą kolekcją 308 11.3. Dostosowywanie wyświetlania 309 Formatowanie wartości 310 Konwertowanie wartości podczas wiązania 310 Zapewnianie domyślnych wartości awaryjnych 314 Obsługiwanie wartości null 314 11.4. Tworzenie szablonów danych 315 Korzystanie z szablonu danych dla kontrolki ContentControl 316 Obrazowanie kontrolki ItemsControl przy pomocy szablonu danych 317 11.5. Podsumowanie 318 12. Kontrolki danych: DataGrid i DataForm 319 12.1. DataGrid 320 Wyświetlanie danych 320 Edytowanie danych siatki 326 Sortowanie elementów 327
viii Spis treści 12.2. DataForm 328 Wyświetlanie danych 329 Wiązanie z listą danych 331 Dostosowywanie wyświetlania 334 Dostosowywanie szablonów edycji, dodawania i wyświetlania 336 Dokładniejsza kontrola nad edycją i zatwierdzaniem danych 338 12.3. Adnotacje dotyczące wyświetlania danych 339 Atrybut Display 340 Atrybut Editable 342 12.4. Podsumowanie 343 13. Sprawdzanie poprawności danych wejściowych 344 13.1. Przykładowe źródło i interfejs użytkownika dla sprawdzania poprawności 346 13.2. Sprawdzanie poprawności właściwości oparte na wyjątkach 349 Obsługa błędów sprawdzania poprawności 350 Niestandardowy kod sprawdzania poprawności 350 Wyświetlanie błędów sprawdzania poprawności 352 13.3. Synchroniczne sprawdzanie poprawności przy pomocy IDataErrorInfo 353 Interfejs IDataErrorInfo 353 Proste sprawdzanie poprawności przy pomocy IDataErrorInfo 354 Sprawdzanie poprawności wielu pól przy pomocy IDataErrorInfo 355 Połączenie wyjątków i interfejsu IDataErrorInfo 358 13.4. Asynchroniczne sprawdzanie poprawności przy pomocy INotifyDataErrorInfo 359 Interfejs INotifyDataErrorInfo 359 Implementacja interfejsu 360 Obsługa wiązania 361 Budowanie usługi WWW przy pomocy WCF 362 Dodawanie kodu obsługowego po stronie klienta 362 Modyfikacje właściwości 364 13.5. Adnotacje dotyczące sprawdzania poprawności 365 Atrybuty sprawdzania poprawności 366 Adnotacje dla naszego elementu 367 Wywoływanie zewnętrznych funkcji sprawdzających poprawność 368 Tworzenie niestandardowych elementów sprawdzających poprawność danych 370 13.6. Porównanie sposobów sprawdzania poprawności 372 13.7. Podsumowanie 373 14. Sieć i komunikacja 374 14.1. Zaufanie, bezpieczeństwo i ograniczenia przeglądarki 375 Dostęp sieciowy pomiędzy domenami 375 Zabezpieczanie aplikacji 379 Ograniczenia przeglądarki 380 14.2. Łączenie się ze źródłami danych 382
Spis treści ix Korzystanie z usług SOAP 382 Usługi REST 391 14.3. Kliencki stos HTTP 396 Ręczne tworzenie stosu klienckiego 396 Automatyczne korzystanie ze stosu klienckiego 396 Automatyczne ustawianie HTTP Referer i innych nagłówków 397 Poświadczenia uwierzytelniające 398 Zarządzanie plikami cookie przy pomocy obiektu CookieContainer 400 14.4. Robienie użytku z danych 401 Odczytywanie danych POX 402 Konwertowanie danych JSON 406 14.5. Korzystanie z usług zaawansowanych 408 Usprawnienia usług WCF 408 Dupleksowe usługi WCF 409 Łączenie się z gniazdami sieciowymi 415 Gniazda rozgłoszeniowe 417 14.6. Łączenie się z innymi aplikacjami Silverlight 420 Tworzenie odbiorcy 421 Tworzenie nadawcy 422 Łączenie wszystkiego razem 422 14.7. Podsumowanie 424 15. Nawigacja i okna dialogowe 426 15.1. Zarys nawigacji w przeglądarce 427 Dzienniki przeglądarek 428 Łącza wykorzystujące znaczniki zakładek 428 Tam i z powrotem 430 15.2. Szablon Navigation Application 430 Tworzenie aplikacji nawigacyjnej 431 Dodawanie nowej strony 432 Zmienianie tematu aplikacji 435 15.3. Nawigowanie do innych stron 436 Klasa Page 437 Klasa NavigationService 438 Ramki i identyfikatory URI 441 Przechowywanie stron w pamięci podręcznej 444 Nawigowanie do stron w innych podzespołach 446 15.4. Nawigacja poza przeglądarką 448 Zapewnianie niestandardowych kontrolek nawigacyjnych 449 15.5. Wyświetlanie okien dialogowych i wyskakujących 454 Kontrolka Popup 454 Wyświetlanie okna dialogowego przy pomocy kontrolki ChildWindow 455 Prośba o wybór pliku 459 15.6. Podsumowanie 462 16. Tworzenie struktury i testowanie aplikacji w oparciu o wzorzec MVVM/ViewModel 464 16.1. Konfigurowanie projektu i tradycyjne podejście wykorzystujące kod stron 466 Konfiguracja projektu i usługi 466 Typowe rozwiązanie z kodem stron 470
x Spis treści 16.2. Podstawy wzorca Model-View-ViewModel 474 Podstawowa implementacja modelu widoku (ViewModel) 477 16.3. Wyodrębnianie kodu wielokrotnego użytku 483 Reguły i logika biznesowa 483 Dostęp do danych i wywołania usługi 485 16.4. Lepsze oddzielenie od interfejsu użytkownika 488 Korzystanie z poleceń 488 Korzystanie z zachowania CallMethodAction 491 Jednostki i modele widoku specyficzne dla danego widoku 493 Interfejsy, odwrócenie sterowania i lokalizatory modeli widoków 498 16.5. Testowanie 502 Wprowadzenie do platformy Silverlight Unit Testing Framework 502 Testowanie modelu widoku 506 Testowanie działań asynchronicznych 507 16.6. Podsumowanie 509 17. Usługi WCF RIA Services 510 17.1. Architektura, narzędzia i szablon usług WCF RIA Services 512 Narzędzia RIA Services 513 Tworzenie projektu przy pomocy szablonu 514 17.2. Udostępnianie danych w usłudze domenowej 517 Tworzenie usługi domenowej 517 Udostępnianie usługi domenowej innym klientom 519 Typy metod usługi domenowej 524 Korzystanie z usługi domenowej z poziomu Silverlight 530 17.3. Filtrowanie, sortowanie, grupowanie i stronicowanie 534 Filtrowanie 534 Sortowanie 538 Grupowanie 539 Stronicowanie 540 17.4. Aktualizowanie danych 543 Korzystanie z interfejsu użytkownika DataForm 543 Kontekst domenowy 545 Klasa Entity 547 Korzystanie z metadanych sprawdzania poprawności i wyświetlania 549 17.5. Luźne sprzężenie: korzystanie z modeli prezentacyjnych 551 Tworzenie modelu prezentacyjnego dla pracownika 552 Obsługa operacji zapytań 554 Obsługa operacji aktualizacyjnych 556 Obsługa operacji wstawiania danych 557 17.6. Logika biznesowa 559 Logika biznesowa w jednostkach danych 560 Udostępnianie kodu 560 17.7. Uwierzytelnianie i autoryzacja 561 Uwierzytelnianie 562 Autoryzacja 565 17.8. Podsumowanie 567
Spis treści xi Część 3 Uzupełnianie interfejsu...................... 569 18. Grafika i efekty 571 18.1. Kształty 572 Line 573 Rectangle 573 Ellipse 574 Polyline 575 Polygon 576 18.2. Geometry 577 Proste geometrie 577 Geometrie ścieżkowe 579 Geometrie złożone 580 18.3. Pędzle 581 SolidColorBrush 581 LinearGradientBrush 582 RadialGradientBrush 585 ImageBrush 587 VideoBrush 587 18.4. Efekty 589 Korzystanie z efektów wbudowanych 589 Tworzenie niestandardowych procedur cieniowania pikseli 593 18.5. Podsumowanie 599 19. Drukowanie 600 19.1. Jak działa drukowanie w Silverlight 601 Klasa PrintDocument 602 Zdarzenie PrintPage 606 Rasteryzacja 608 19.2. Drukowanie informacji ekranowych 609 Drukowanie zawartości tak, jak na ekranie 610 Przenoszenie elementów do innego elementu głównego 612 Skalowanie zawartości 613 19.3. Drzewa wizualne dedykowane do drukowania wielostronicowego 616 Wymagania wstępne 617 Drukowanie elementów z wierszami raportu 621 Dodawanie obsługi wielu stron 627 Dodawanie nagłówka i stopki 629 19.4. Podsumowanie 633 20. Wyświetlanie i przechwytywanie multimediów 634 20.1. Audio i wideo 635 Źródło multimediów 635 Często używane właściwości 641 Właściwości specyficzne dla audio 644 Właściwości specyficzne dla wideo 645 Cykl życia pliku multimedialnego 646 20.2. Listy odtwarzania 648 Zrozumienie list odtwarzania po stronie klienta 648 Korzystanie z list odtwarzania po stronie serwera 650 20.3. Interaktywne odtwarzanie 652 Kontrolowanie stanu odtwarzania 652 Praca z linią czasu 653
xii Spis treści 20.4. Korzystanie z zawartości zabezpieczonej 655 Korzystanie z zawartości chronionej 655 Pobieranie składników PlayReady 656 Odblokowywanie zawartości zabezpieczonej 656 20.5. Korzystanie z platformy Silverlight Media Framework 657 Korzystanie z bibliotek odtwarzacza 658 Tworzenie odtwarzacza 659 20.6. Praca z surowymi multimediami 661 Niestandardowa klasa MediaStreamSource 661 Tworzenie surowego wideo 663 Tworzenie surowego audio 668 20.7. Korzystanie z kamery internetowej 673 Uzyskiwanie dostępu do urządzeń przechwytujących 673 Praca z wideo 675 Przechwytywanie obrazów nieruchomych 678 Pozyskiwanie danych surowego wideo 681 Uwaga na temat audio 683 20.8. Podsumowanie 684 21. Praca z obrazami bitmapowymi 685 21.1. Podstawowa obsługa obrazów 686 21.2. Tworzenie obrazów w trakcie działania aplikacji 687 Tworzenie obrazów na podstawie istniejących obrazów 688 Tworzenie obrazu z elementów interfejsu użytkownika 690 Generator fraktala Mandelbrota 692 21.3. Deep Zoom 695 Wyświetlanie obrazu 695 Przybliżanie i oddalanie obrazu 696 Zarządzanie oknem widoku 698 Wdrażanie obrazów wielkoformatowych 699 21.4. Radzenie sobie z pustym miejscem 700 Wypełnianie przestrzeni 701 Rozciąganie proporcjonalne 702 Wypełnianie obszaru 703 UniformToFill 704 21.5. Podsumowanie 705 22. Animacja i zachowania 706 22.1. Animacja: chodzi o czas 707 22.2. Opanowywanie linii czasu 708 Jaki jest typ animowanej właściwości? 709 Od czego zaczynamy i do czego zmierzamy? 711 Jak długo powinna trwać animacja? 714 22.3. Korzystanie z planów animacji 717 Zrozumienie planu animacji 717 Trafianie w cel 718 Kontrola elementu Storyboard 721 Animacje w zasobach 722 22.4. Klatki kluczowe 725 Interpolacja: chodzi o przyspieszenie 727
Spis treści xiii 22.5. Funkcje łagodzące 731 Korzystanie z funkcji łagodzących 732 Tworzenie niestandardowej funkcji łagodzącej 734 22.6. Zachowania, wyzwalacze i działania 736 Korzystanie z istniejących zachowań 738 Tworzenie swojego własnego zachowania 739 22.7. Podsumowanie 741 23. Zasoby, style i szablony kontrolek 742 23.1. Korzystanie z zasobów 743 Zasoby deklaratywne 743 Dostęp do zasobów luźnych 750 Zasoby spakowane 751 23.2. Nadawanie stylu elementom 754 Definiowanie wyglądu 755 Definicje stylów z jawnymi kluczami 757 Definicje stylów niejawnych 758 23.3. Tworzenie szablonów 760 Budowanie szablonu kontrolki 760 Tworzenie szablonów wielokrotnego użytku 765 23.4. Obsługa stanów wizualnych 766 Zrozumienie składników 766 Korzystanie z możliwości VisualStateManager 768 23.5. Udostępnianie naszych stanów wizualnych 772 23.6. Podsumowanie 773 24. Panele i kontrolki 774 24.1. Tworzenie niestandardowego panelu 775 Przygotowanie projektu 776 Klasa OrbitPanel 776 Właściwości 777 Układ niestandardowy 780 Usprawnienia 785 24.2. Tworzenie niestandardowej kontrolki 786 Wybieranie typu bazowego 787 Właściwości 788 Kontrakt dla szablonu kontrolki 789 Szablon domyślny 790 Stany wizualne 791 Stany wizualne w szablonie 793 24.3. Podsumowanie 795 25. Interfejs instalacji i ładowania 796 25.1. Obsługa scenariuszy, gdy Silverlight nie jest zainstalowany 797 Tworzenie swojego własnego interfejsu instalacji 798 25.2. Korzystanie z niestandardowego modułu ładującego 800 Tworzenie wyglądu 801 Integracja niestandardowego ekranu tytułowego 803 Monitorowanie postępu ładowania 804 25.3. Podsumowanie 805
xiv Spis treści A. Konfiguracja bazy danych, połączenia i modelu danych 807 A.1. Instalacja bazy danych AdventureWorks 807 Instalowanie na dedykowanym wystąpieniu SQL Server 808 Instalowanie w SQL Server Express 808 A.2. Połączenie bazodanowe i jednostki danych 809 Wybór jednostek do utworzenia 812 Indeks 850
Wstęp Zajmuję się programowaniem aplikacji klienckich. Zaczynałem w szkole od komputera Commodore 64 w latach osiemdziesiątych, później przeszedłem do systemu DOS pracując z technologiami dbase, QuickBasic i C++, a w końcu zająłem się programowaniem dla systemu Windows przy użyciu C++, Borland Delphi 1.0, PowerBuilder, Visual Basic 3 6 oraz.net. Choć napisałem mnóstwo aplikacji WWW korzystających wyłącznie z HTML/JavaScript, to zawsze wolałem programowanie klienckie od ścisłego programowania dla WWW, ponieważ czułem, że programowanie w HTML/JavaScript traktuje komputer PC jak głupi terminal trwoniąc cykle procesora na aplikacje, których wydajność niemal w całości zależy od sieci. Dopiero niedawno się to zmieniło. Gdy aplikacje WWW zaczynały stawać się popularne, klientom podobała się elastyczność pustej strony HTML wobec starego, szarego wyglądu aplikacji Windows, a także łatwość wdrażania aplikacji WWW. Po stronie programowania aplikacji klienckich mieliśmy kilka zbliżonych technologii (na przykład WPF, jeśli chodzi o wygląd), ale nic, co łączyłoby łatwość wdrażania z nowoczesnym wyglądem. Przez chwilę wyglądało to tak, jakby świat zamierzał przejść na względnie ograniczone aplikacje WWW traktując lokalny komputer jako jedynie klawiaturę i ekran co wydawało się rozczarowującym posunięciem. W roku 2006, na długo zanim dostałem pracę jako Silverlight and WPF Community PM w Microsoft, uczestniczyłem w pierwszej konferencji MIX w Las Vegas. 21 marca, w drugim dniu konferencji, brałem udział w kilku sesjach dotyczących WPF/E, produktu, który później został przemianowany na Silverlight. Już wtedy firma Microsoft miała dla Silverlight przygotowaną wizję, która obejmowała komputery osobiste, urządzenia mobilne i dedykowane. Miała to być lżejsza wersja WPF zoptymalizowana pod kątem scenariuszy wieloplatformowych, która korzystałaby zarówno z siły przetwarzania po stronie klienta (po włączeniu.net CLR do tej technologii), jak i zapewniała łatwość wdrażania tradycyjnych aplikacji WWW. Dokładnie tego szukałem! Byłem wtedy dość zafascynowany technologią WPF/E. Martwiłem się też nieco argumentami za przyjęciem się tej technologii. Postanowiłem poczekać i zobaczyć, co się stanie. Gdy pojawiły się wersje Silverlight 1.0 CTP i beta, nie byłem zbyt zachwycony, ponieważ
xvi Wstęp wykorzystywały jedynie JavaScript. Nie byłem wtedy wielkim fanem JavaScript i czułem, że technologia WPF/E nie będzie miała żadnego istotnego znaczenia, dopóki nie spełni obietnicy wykorzystania CLR w przeglądarce. Tak czy owak, w roku 2007 zająłem się projektem stworzenia kalkulatora redukcji emisji dwutlenku węgla w technologii WPF/E, który miał być dostępny w SharePoint na publicznej witrynie internetowej. Później na konferencji MIX07 nazwa Silverlight została nadana technologii WPF/E. Równocześnie firma Microsoft wprowadziła wersję Silverlight 1.1, która działała z kodem zarządzanym i zawierała międzyplatformową wersję.net CLR. Hurra! Koniec z JavaScript! (Cóż, było to, zanim projekt jquery udowodnił mi, że język JavaScript też może być wspaniały). W tym momencie namawiałem sponsorów projektu, aby pozwolili nam pracować w technologii Silverlight 1.1a. Rozmawiałem też z pewnymi osobami w Microsoft i uzyskałem pozwolenie na użycie Silverlight 1.1a w publicznej aplikacji narzucając kod w stadium alfa niczego nie spodziewającym się użytkownikom. Pomimo (lub może z powodu) konieczności kodowania wielu podstawowych elementów od zera (potrzebowaliśmy przycisków i list rozwijanych, które nie istniały w wersji Silverlight 1.1a), zostałem całkowicie zauroczony. Czułem się, jak w dawnych czasach programowania dla systemu DOS, gdy trzeba było błąkać się bez istotnego wsparcia i wymyślać swoje własne sztuczki w celu osiągnięcia pożądanych celów. To był dziki zachód programowania (i mam tu na myśli dziki zachód z dodanymi gigantycznymi steampunkowymi pająkami). Nadal mam miejsce w sercu dla starszego brata Silverlight WPF, ale łatwo było dostrzec, że to Silverlight zdobędzie świat szturmem. WPF jest wciąż niezwykle potężną technologią, ale wydaje się bardziej podobać użytkownikom niszowym i niezależnym twórcom oprogramowania, niż szerokiej grupie tworzącej zawodowo aplikacje oparte na WWW. Pracując w zespole tworzącym kalkulator emisji dwutlenku węgla wypuściliśmy na rynek pierwszą aplikację Silverlight w kodzie zarządzanym. Zawierała ona wideo, integrację z serwisem Windows Live Maps, integrację przez usługi WWW z SharePoint, oczywiście obliczenia dotyczące redukcji emisji oraz konfigurowalny interfejs użytkownika całkowicie sterowany przez dane, z portalem SharePoint utrzymującym całość. Nie było wtedy prawdziwego ekosystemu związanego z Silverlight, a pomysł współpracy z projektantami przy tworzeniu aplikacji klienckich w technologiach Microsoft nie był jeszcze powszechny. Pomimo prymitywnego interfejsu użytkownika, który zaprojektowaliśmy, nadal jestem dumny z tego, co stworzyliśmy. Byłem podekscytowany możliwością wykorzystania swoich umiejętności.net w czymś nowym i wyjątkowym. Później tego roku wersja Silverlight 1.1a została zaktualizowana do silniejszego podzbioru WPF i przemianowana na Silverlight 2, co położyło podstawy konieczne dla Silverlight 4 edycji, która nadal mnie codziennie fascynuje, gdy z niej korzystam. Pete Brown
Podziękowania Książka taka, jak ta, jest wysiłkiem zbiorowym od początku do końca. Choć moje nazwisko jest na okładce, to nie mógłbym ukończyć tej książki bez wsparcia i ciężkiej pracy wielu innych osób. Wymienię tych, którym należą się podziękowania i przepraszam tych, których być może powinienem także wymienić: Chad Campbell i John Stockton za stworzenie tak świetnego pierwszego wydania. Bez ich ciężkiej pracy obejmującej Silverlight 2, nigdy nie pomyślałbym nad stworzeniem wydania dla wersji Silverlight 4. Marshal Agnew, Brendan Clark i Jordan Parker z zespołu produktowego Silverlight za ich pomoc w dokopywaniu się do najgłębszych czeluści systemu obrazowania i układu. Gdyby nie te osoby, nie byłbym w stanie zapewnić tego poziomu szczegółowości, który zawarłem w rozdziale 6. David Ferguson i Seema Ramchandani z zespołu produktowego Silverlight za pomoc w kwestiach wydajnościowych dotyczących transformacji. Tim Heuer z zespołu produktowego Silverlight za pomoc dotyczącą interfejsu instalacyjnego Silverlight, omawianego w rozdziale 25. Jeff Handley z zespołu produktowego usług WCF RIA Services za przejrzenie rozdziału dotyczącego usług RIA Services. Ashish Shetty z zespołu produktowego Silverlight za zachęcenie mnie do blogowania na temat Silverlight, w tym na temat modelu aplikacji i procesu uruchamiania, co wykorzystałem też w tej książce. Tom McKearney, Tad Van Fleet, Al Pascual i Ben Hayat za świetne recenzje techniczne. Wyłapali oni mnóstwo błędów, między innymi związanych z różnicami pomiędzy wersjami Silverlight 2, 3 i 4 oraz zmianami pomiędzy wcześniejszymi edycjami a końcowym wydaniem wersji Silverlight 4. René Schulte za pomoc w zaktualizowaniu podrozdziałów dotyczących obrazowania i procedur cieniowania pikseli. René jest ekspertem od pracy z bitmapami i procedurami cieniowania. Mike Street z forów za pomocne i dokładne recenzje wielu rozdziałów na forach. Mike był świetnym, nieoficjalnym recenzentem technicznym tej książki.
xviii Podziękowania Ponadto wielu redaktorów, korektorów i recenzentów w wydawnictwie Manning Publications zasługuje na podziękowania za ciężką pracę. Dostarczyłem im książkę dwa razy większą, niż się spodziewali przy krótszym okresie produkcyjnym niż normalnie. Osoby takie, jak Benjamin Berg, Mary Piergies, Nermina Miller, Gordan Salinovic i inni pracowały niestrudzenie, aby wydać tę książkę na czas. Dziękuję im i pozostałym pracownikom wydawnictwa Manning za wyrozumiałość, gdy terminy pracy nad książką nie były dotrzymywane, powstało trzymiesięczne opóźnienie, a książka okazała się dwa razy grubsza, niż zakładano. Szczególne podziękowania kieruję do swojego redaktora Jeffa Bleiela. To była pierwsza książka, jaką napisałem, więc nie byłem pewien, czego się spodziewać. Dobry redaktor może sprawić, że autorowi będzie się pracowało dobrze, a nie okropnie. Jeff był z pewnością świetnym redaktorem, respektował nasze odrębne kompetencje i starał się utrzymać pracę nad książką na właściwym torze. Był moim interfejsem z wydawnictwem Manning i moim mentorem jako autora. Jeff pozytywnie wpłynął na tę książkę i ogólnie na moje pisanie. Oprócz pojedynczych osób, które pomagały mi nad samą książką, są jeszcze ci, którzy pomogli w jej powstaniu przez swoją obecność lub działania. Przede wszystkim dziękuję swojej żonie Melissie za bycie samotną mamą przez większość roku 2010 i swoim dzieciom Benowi i Abby za zrozumienie, gdy mama mówiła im, że tata pisze i nie może się teraz bawić. Pisanie książki o takich rozmiarach dotyczącej produktu, który zmienia się co 10 lub 12 miesięcy, jest przedsięwzięciem angażującym całą rodzinę. Chciałbym podziękować swojemu szefowi w firmie Microsoft, Scottowi Hanselmanowi, za to, że zapewnił mi czas na ukończenie tej książki. Napisanie tej książki zajęło mnóstwo czasu i gdyby Scott nie dał mi nieco swobody, to po prostu nie zostałaby ukończona. Oczywiście dziękuję społeczności Silverlight i WPF, swoim przyjaciołom z serwisu Twitter, pracownikom zajmującym się Silverlight i WPF, posiadaczom tytułów MVP oraz wszystkim, którzy czytali i komentowali moje wpisy w blogu od pierwszego wydania Silverlight. Wsparcie społeczności dla tych technologii motywowało mnie do stworzenia jak najlepszej książki. Jestem też wdzięczny swojej mamie za zachęcanie mnie do pracy z komputerem i pomoc w uzyskaniu pierwszej pracy związanej z napisaniem aplikacji bazodanowej w C++. Bez niej nie byłbym dzisiaj w tym miejscu. Chciałbym podziękować swojemu tacie, który zmarł, podczas gdy pisałem tę książkę. Nigdy dobrze nie rozumiał, co robiłem na tym komputerze Commodore w swoim pokoju wpisując kod szesnastkowy z czasopism, ale wspierał mnie od początku i zachęcał mnie do podjęcia kariery związanej z tym, co lubię. Wreszcie chciałbym podziękować swoim Czytelnikom.
Informacje na temat tej książki Ogólnym celem tej książki jest informacja i nauczenie ekscytującej platformy Silverlight 4. Można ją traktować jako przewodnik po wtyczce, bibliotekach uruchomieniowych i pakiecie SDK Silverlight 4. Po przeczytaniu tej książki można z powodzeniem projektować, programować i dostarczać bogate, interaktywne aplikacje wykorzystujące Silverlight. Aby ułatwić proces uczenia, opracowałem tę książkę tak, żeby można było zacząć programowanie tak szybko, jak to możliwe, zapewniając przy tym rozbudowaną, dogłębną treść. W każdym rozdziale zawarłem kilka elementów pomagających lepiej zrozumieć Silverlight. Następująca lista wyjaśnia, jak każdy z tych czynników pomaga w tym procesie: Rysunki Wizualne przedstawienia danych i skomplikowanych pojęć. Wydruki niewielkie, zwarte fragmenty kodu, używane głównie do prezentacji formatów składniowych. Te pojedyncze fragmenty zwykle nie mogą być uruchamiane samodzielnie. Tabele Łatwe w czytaniu podsumowania. Oprócz tych elementów, moja osobista witryna http://10rem.net zawiera łącza do przykładów kodu użytych w tej książce. Dodatkowo witryna http://silverlightinaction.com dla pierwszego wydania zawiera zasoby, obrazy i usługi wykorzystywane w tej książce. Do kogo jest kierowana ta książka? Ta książka jest przeznaczona dla programistów, którzy chcą tworzyć nietrywialne aplikacje przy pomocy Microsoft Silverlight 4. Chociaż Silverlight zapewnia liczne możliwości interakcji z projektantami, ta książka jest przeznaczona głównie do osób, które żyją i oddychają w Visual Studio. Informacje te będą też przydatne i cenne dla członków zespołów w roli integratorów (tych, którzy zajmują się projektami i implementują je w Silverlight). Ta książka zakłada co najmniej ogólną znajomość typowych standardów internetowych, takich jak HTML, CSS, XML i JavaScript. Ponadto ta książka zakłada pewne doświadczenie w korzystaniu z platformy.net i Microsoft Visual Studio. Choć będziemy korzystać z C# jako głównego języka programowania, to nie będziemy opisywać języka C#, ani wyjaśniać podstawowych konstrukcji programistycznych, takich jak klasy, metody i zmienne.
xx Informacje na temat tej książki Do korzystania z tej książki nie jest wymagane doświadczenie w używaniu wcześniejszych wersji Silverlight. Jakie elementy są nam potrzebne? Ta książka zapewnia wiele okazji do nauki. Zapewnia również dużo elastyczności pozwalając na poznawanie materiału bez korzystania z praktycznych przykładów lub narzędzi opcjonalnych. Jeśli chcemy maksymalnie skorzystać z tej książki i przykładów praktycznych, to zalecane są następujące narzędzia: Visual Studio 2010 Pro lub wyższa wersja albo Visual Studio Web Developer 2010 (darmowy) Silverlight 4 tools for Visual Studio 2010, w tym pakiet Silverlight 4 SDK i WCF RIA Services 1.0 Pakiet Silverlight toolkit Microsoft Expression Blend 4 (opcjonalnie) Microsoft Expression Blend 4 SDK for Silverlight 4 (instalowany z Blend 4) do tworzenia i korzystania z zachowań Łącza do wszystkich tych narzędzi znajdziemy pod adresem http://silverlight.net/ GetStarted. Mapa drogowa Ta książka jest zaprojektowana jako praktyczny przewodnik po Silverlight 4. Skupia się na trzech głównych obszarach: wprowadzeniu do Silverlight, strukturze aplikacji i uzupełnieniach. I.1.1 Część 1: Wprowadzenie do Silverlight Rozdział 1 stanowi wprowadzenie do Silverlight. Ten wstęp pokazuje nam zalety Silverlight i wyjaśnia miejsce tej technologii na arenie aplikacji klienckich i internetowych. Ten rozdział kończy się instrukcją budowania pierwszej aplikacji Silverlight. Rozdział 2 omawia jedną z najbardziej fundamentalnych części Silverlight: XAML. Choć większość tej książki dotyczy języka XAML w takiej, czy innej formie, ten rozdział przechodzi od podstaw aż do drzew wizualnych i logicznych, systemu właściwości zależnościowych i rozszerzeń XAML. Rozdział 3 wyjaśnia, jak działa wtyczka Silverlight i proces uruchamiania aplikacji. Poznamy obiekt aplikacji, plik.xap i przechowywanie podzespołów w pamięci podręcznej. Przypatrzymy się też, jak inicjować wtyczkę i korzystać z niej na stronie WWW. Rozdział 4 rozwija zagadnienie integracji z przeglądarką wprowadzone w rozdziale 3 i pokazuje, jak manipulować modelem HTML DOM z poziomu Silverlight, pracować z oknem przeglądarki oraz łączyć światy skryptowy i zarządzany. Ten rozdział wprowadza również
Mapa drogowa xxi kontrolkę WebBrowser używaną do wyświetlania zawartości WWW w Silverlight podczas działania aplikacji poza przeglądarką. W rozdziale 5 opuszczamy środowisko WWW i przechodzimy do pulpitu. Silverlight obsługuje tworzenie aplikacji pulpitowych działających zarówno z ograniczeniami, jak i z podwyższonym zaufaniem. Ten rozdział obejmuje aplikacje uruchamiane poza przeglądarką, dostęp do plików lokalnych, automatyzację COM, niestandardową otoczkę okien, pracę na pełnym ekranie i wykorzystanie pamięci izolowanej. Rozdział 6 obejmuje system układu i obrazowania, a także transformacje dwuwymiarowe i trójwymiarowe. Jeśli naprawdę chcemy zrozumieć, co się dzieje, gdy umieszczamy piksele na ekranie, to wiedza o systemie układu i obrazowania jest koniecznością. Dla mnie osobiście te informacje są niezwykle interesujące; mam nadzieję, że dla innych również. Rozdział ten obejmuje też transformacje dwuwymiarowe, takie jak pochylenie i przesunięcie oraz trójwymiarowe rzutowanie płaskie i matrycowe. Rozdział 7 rozwija informacje o układzie z rozdziału 6, żeby pokazać, jak korzystać z różnych typów paneli w Silverlight, w tym Grid, StackPanel i Canvas. Rozdział 8 zajmuje się czynnikiem ludzkim. Wszystkie dotychczasowe rozdziały dotyczyły prezentacji, a ten dotyczy zbierania informacji. Dowiemy się, jak korzystać z klawiatury, myszy, wirtualnego atramentu i interfejsów dotykowych do przeprowadzania działań w naszych aplikacjach. Rozdział 9 obejmuje wejście i wyjście tekstowe. Zaczynam od omówienia technologii tekstowych, w tym od informacji o strategiach wygładzania czcionek oraz typowych właściwościach tekstowych kontrolek i elementu TextBlock. Następnie przyjrzę się kontrolkom do wprowadzania tekstu, takim jak TextBox i RichTextBox z dygresjami na temat edytorów IME i tekstu międzynarodowego. Rozdział 10 wprowadza kilka kontrolek niezwiązanych z tekstem, w tym Button, RadioButton, CheckBox, ComboBox, ListBox i inne. Ten rozdział obejmuje też bazowe typy kontrolek dla wbudowanych i niestandardowych kontrolek, takie jak ContentControl i ItemsControl. I.1.2 Część 2: Struktura aplikacji Rozdział 11 obejmuje wiązanie. W Silverlight nie powinniśmy przypisywać wartości bezpośrednio do kontrolek w kodzie strony. Wiązanie jest jedną z najważniejszych funkcji Silverlight i będziemy się nim dalej zajmowali w kolejnych rozdziałach. Rozdział 12 rozwija to, co poznaliśmy w rozdziale 11 i wykorzystuje kontrolki DataGrid oraz DataForm. W tym rozdziale omawiam też zastosowanie adnotacji danych do sterowania atrybutami wyświetlania dla naszych jednostek. Rozdział 13 również rozszerza informacje z rozdziału 11 i 12, żeby zapewnić możliwości sprawdzania poprawności w naszych aplikacjach. Omawiam sprawdzanie poprawności oparte na wyjątkach, synchroniczne i asynchroniczne sprawdzanie poprawności przy użyciu interfejsów, sprawdzanie poprawności z wykorzystaniem atrybutów oraz tworzenie swoich własnych, niestandardowych procedur sprawdzania poprawności.
xxii Informacje na temat tej książki Rozdział 14 pomaga naszym aplikacjom Silverlight komunikować się z serwerami w Internecie i intranecie. W tym rozdziale dowiadujemy się, jak korzystać z usług SOAP i REST, stosu WWW, gniazd, a nawet lokalnych połączeń pomiędzy aplikacjami Silverlight. Rozdział 15 zajmuje się wykorzystaniem platformy Navigation Framework, okien i okien dialogowych w naszych aplikacjach. Przyjrzymy się, jak zorganizować strukturę swojej aplikacji w postaci ciągu stron, obsługiwać adresy i mapowania URL oraz przekazywanie parametrów. Zapoznamy się też z wbudowanymi oknami dialogowymi i klasą ChildWindow. Rozdział 16 omawia wzorzec MVVM i testy jednostkowe. Bez wybierania konkretnej platformy MVVM (albo ViewModel) pokażę pojęcia stojące za wzorcem ViewModel i sposoby ich implementacji w swoich własnych aplikacjach. Ten rozdział zamyka się informacjami dotyczącymi testowania aplikacji Silverlight przy pomocy platformy Silverlight Unit Testing Framework. Rozdział 17 omawia jeden z najbardziej ekscytujących elementów aplikacji biznesowych lub zorientowanych na dane: usługi WCF RIA Services. Omówimy tworzenie aplikacji RIA z wykorzystaniem szablonu Business Application i przyjrzymy się wszystkiemu od zapytań i operacji aktualizujących do reguł biznesowych, sprawdzania poprawności i zabezpieczeń. I.1.3 Część 3: Uzupełnianie interfejsu Rozdział 18 zajmuje się grafiką wektorową i pędzlami kluczowymi pojęciami przy tworzeniu aplikacji, które nie ograniczają się do zwykłych kontrolek. Ten rozdział omawia też efekty i procedury cieniowania pikseli, zamykając się informacjami na temat budowania swojej własnej, niestandardowej procedury cieniowania pikseli w językach HLSL i C#. Rozdział 19 omawia pracę z drukarką z poziomu Silverlight. Wersja Silverlight 4 wprowadziła możliwość drukowania krótkich dokumentów lub obsługi funkcjonalności drukowania zawartości ekranu. Omawiamy interfejs API i podsumowujemy ten rozdział implementacją niestandardowego rozwiązania raportującego do tworzenia krótkich raportów. Rozdział 20 jest w całości poświęcony multimediom: wideo i audio. W tym rozdziale omawiam różne sposoby przedstawiania zawartości wideo i audio w naszej aplikacji, w tym technologię IIS Smooth Streaming i niestandardowe kodeki tworzone w kodzie zarządzanym przy użyciu MediaStreamSource. Zajmuję się też interfejsem API dla kamer internetowych i mikrofonów omawiając podstawy ich użycia, a także tworząc własną klasę VideoSink do manipulowania zwróconymi danymi. Rozdział 21 zajmuje się nieruchomymi obrazami. W tym rozdziale przyglądamy się, jak korzystać z obrazów bitmapowych w swojej aplikacji, w tym poznajemy podejścia do generowania obrazów w trakcie działania programu. Rozdział 22 omawia animację i zachowania. Dowiemy się, jak korzystać z planów animacji do ożywienia swojego interfejsu. Następnie przyjrzymy się wykorzystywaniu i tworzeniu zachowań opakowujących funkcjonalność wielokrotnego użytku, często z zastosowaniem animacji. Rozdział 23 omawia style, szablony i zasoby. Przyjrzymy się, jak opakowywać informacje o stylach dla kontrolek i jak tworzyć całkiem nowe szablony wykorzystując model kontrolek bez wyglądu.
Konwencje dotyczące kodu i materiały do pobrania xxiii Rozdział 24 nauczy nas, jak tworzyć niestandardowe panele i kontrolki. Choć w Silverlight prawie wszystko możemy zrobić przy użyciu nowego szablonu kontrolki, to czasem musimy utworzyć swoją własną kontrolkę lub panel. Rozdział 25 zamyka tę książkę informacjami na temat tworzenia najlepszego, możliwego interfejsu instalacyjnego dla wtyczki, a także najlepszego interfejsu ładowania naszych aplikacji. Konwencje dotyczące kodu i materiały do pobrania Cały kod w tej książce jest przedstawiany przy użyciu czcionki z literami o jednakowej szerokości. Kod ten może być pisany w różnych językach programowania, używany język jest podany na początku bloku kodu. Przy dłuższych wierszach kodu może być używany znak zawijania wiersza, żeby poradzić sobie z ograniczeniami drukowanej strony. Adnotacje towarzyszą wielu wydrukom kodu, a numerowane wskaźniki są używane, gdy potrzebne są dłuższe wyjaśnienia. Kod źródłowy dla wszystkich przykładów w tej książce jest dostępny do pobrania z witryny WWW wydawcy pod adresem www.manning.com/silverlight4inaction i z witryny WWW autora pod adresem http://10rem.net. Autor w sieci Zakup Silverlight 4 w działaniu zawiera darmowy dostęp do prywatnego forum prowadzonego przez wydawnictwo Manning Publications, gdzie można komentować tę książkę, zadawać pytania techniczne i uzyskać pomoc od autora i innych użytkowników. Dostęp do tego forum można uzyskać pod adresem www.manning.com/silverlight4inaction. Strona ta zapewnia informacje dotyczące tego, jak dostać się do forum po zarejestrowaniu, jaki rodzaj pomocy jest dostępny i jakie są zasady postępowania na forum. Wydawnictwo Manning chce zapewniać swoim Czytelnikom miejsce, gdzie mogą prowadzić dialog z autorem oraz między sobą. Nie zobowiązuje to autora do udziału w forum tej książki w jakimś określonym stopniu, jego zaangażowanie jest dobrowolne (i bezpłatne). Zachęcamy do zadawania autorowi wymagających pytań. Forum Author Online i archiwa z wcześniejszymi dyskusjami będą dostępne na witrynie WWW wydawcy tak długo, jak ta książka będzie dostępna w druku. Oprócz forum Author Online na witrynie wydawnictwa można też kontaktować się z nami w sprawach związanych z tą książką i innych, korzystając z jednego z następujących miejsc: Witryny i blogu autora http://10rem.net Konta Pete a w serwisie Twitter http://twitter.com/pete_brown
xxiv Informacje na temat tej książki O autorze Pete Brown pracuje na stanowisku Community Program Manager w firmie Microsoft w zespole zajmującym się społecznością programistów prowadzonym przez Scotta Hanselmana, jest również byłym posiadaczem tytułu Microsoft Silverlight MVP, wykładowcą INETA oraz architektem RIA w Applied Information Sciences, gdzie pracował przez ponad 13 lat. W firmie Microsoft Pete skupia się na społeczności związanej z programowaniem aplikacji klienckich (WPF, Silverlight, Windows Phone, Surface, Windows Forms, C++, Native Windows API, itd.). Od swoich pierwszych grafik i niestandardowych zestawów znaków dla komputera Commodore 64, poprzez modelowanie i projektowanie 3-wymiarowe, aż do programowania dla Silverlight, Surface, XNA i WPF, Pete zawsze dogłębnie interesował się programowaniem, projektowaniem i interfejsami użytkownika. Jego zaangażowanie w technologię Silverlight sięga wstecz aż do aplikacji dla wersji Silverlight 1.1 alpha, które współtworzył i wdrożył do produkcji w czerwcu 2007. Pete programuje dla zabawy od 1984 roku i zawodowo od 1992 roku. W wolnym czasie Pete zajmuje się programowaniem, pisaniem blogu, stolarką i wychowywaniem z żoną dwójki swoich dzieci na przedmieściach Maryland. O tytule Łącząc podstawy, omówienia i przykłady, książki z serii W działaniu mają pomóc w nauce danej technologii. Według badań naukowych ludzie zapamiętują lepiej rzeczy, które odkrywają sami poprzez badanie. W wydawnictwie Manning jesteśmy przekonani, że skuteczne uczenie musi przechodzić przez etapy badania, zabawy i powtarzania poznawanego materiału. Ludzie rozumieją i zapamiętują nowe rzeczy, czyli je opanowują, tylko jeśli aktywnie je badają. Ludzie uczą się w działaniu. Istotną częścią książki z serii W działaniu jest to, że jest prowadzona przez przykłady. Zachęca Czytelnika do wypróbowywania nowych zagadnień, zabawy z nowym kodem i badania nowych pomysłów. Jest też inny, bardziej przyziemny powód dla takiego tytułu książki: nasi Czytelnicy są zajęci. Korzystają z książek w celu wykonania swojej pracy lub rozwiązania jakiegoś problemu. Potrzebują książki, która pozwala im łatwo zapoznać się z określonym zagadnieniem wtedy, gdy tego potrzebują. Potrzebne im są książki, które pomagają im w działaniu. Książki w tej serii są zaprojektowane dla takich Czytelników.
O ilustracji na okładce Rysunek na okładce książki Silverlight 4 w działaniu przedstawia janczara w stroju paradnym. Janczarzy stanowili osobiste oddziały osmańskiego sułtana. Ilustracja pochodzi ze zbioru kostiumów z imperium osmańskiego opublikowanego 1 stycznia 1802 roku przez Williama Millera z Old Bond Street w Londynie. W zbiorze tym brakuje strony tytułowej i jak dotąd nie udało się jej odnaleźć. Spis treści w tej książce opisuje obrazki po angielsku i po francusku, a każda ilustracja opatrzona jest nazwiskami dwóch artystów, którzy nad nią pracowali. Bez wątpienia obaj byliby zaskoczeni odkryciem, że ich dzieło trafi na okładkę książki programistycznej dwieście lat później. Zbiór ten został zakupiony przez redaktora wydawnictwa Manning na antykwarycznym pchlim targu Garage przy West 26th Street na Manhattanie. Sprzedawcą był Amerykanin pochodzący z Ankary w Turcji, a transakcja została dokonana, gdy zaczął już pakować swoje stoisko pod koniec dnia. Redaktor wydawnictwa Manning nie miał przy sobie odpowiedniej ilości gotówki, która była wymagana do zakupu, a sprzedawca grzecznie odmówił przyjęcia karty kredytowej i czeku. Ponieważ sprzedawca miał odlatywać do Ankary tego wieczoru, sytuacja stawała się beznadziejna. Jakie było rozwiązanie? Okazało się, że wystarczy staromodna umowa ustna przypieczętowana uściśnięciem dłoni. Sprzedawca po prostu zaproponował, aby pieniądze zostały mu przekazane przelewem i nasz redaktor oddalił się z informacjami o koncie bankowym na kartce papieru i zbiorem rysunków pod pachą. Nie trzeba dodawać, że przelaliśmy fundusze następnego dnia i jesteśmy wdzięczni tej nieznanej osobie za okazane nam zaufanie. Wygląda to na historię, która mogła się zdarzyć dawno temu. Rysunki ze zbioru osmańskiego, jak inne ilustracje, które pojawiają się na naszych okładkach, przywracają do życia bogactwo i różnorodność strojów sprzed kilku wieków. Przypominają o poczuciu izolacji i oddalenia z tego okresu oraz każdego innego okresu historycznego poza naszą własną hiperkinetyczną teraźniejszością. Etykiety związane z ubiorami zmieniły się od tego czasu, a zróżnicowanie regionalne, które wtedy było tak bogate, rozpłynęło się. Obecnie trudno jest zazwyczaj odróżnić mieszkańca jednego kontynentu od drugiego. Być może, starając się spojrzeć na to optymistycznie, zamieniliśmy różnorodność kulturalną i wizualną na bardziej zróżnicowane życie osobiste albo bardziej różnorodne i interesujące życie intelektualne i techniczne. W wydawnictwie Manning cenimy inwencję, inicjatywę i radość związaną z biznesem komputerowym poprzez okładki książek oparte na bogatej różnorodności życia regionalnego sprzed wieków i przywrócone do życia dzięki rysunkom z tego zbioru.
Część 1 Wprowadzenie do Silverlight Pierwszą część tej książki zaczniemy od zbudowania swojej pierwszej aplikacji Silverlight, a następnie zagłębimy się w mechanizmy kierujące tą technologią. Omówimy język znaczników używany do tworzenia interfejsu, zapoznamy się z modelem aplikacji i przyjrzymy się integracji zarówno z przeglądarką, jak i z pulpitem. Następnie poznamy system kompozycji i panele dwa pojęcia istotne dla skutecznego projektowania interfejsu użytkownika. Część tę zakończymy omówieniem wprowadzania danych przy pomocy myszy, dotyku i klawiatury; wyświetlania i wprowadzania tekstu; oraz dyskusją na temat różnych typów kontrolek powszechnie używanych w projektach.
1 Wprowadzenie do Silverlight Ten rozdział omawia: Silverlight, sieć WWW i WPF Najlepsze aplikacje dla Silverlight Początki pracy z Silverlight Zmiany w technologii Silverlight od pierwszego wydania tej książki Budowanie pierwszej aplikacji w Silverlight Przede wszystkim chciałbym podziękować za rozpoczęcie czytania od rozdziału 1. Należę do tych osób, które zwykle czytają czasopisma od tyłu i pobieżnie kartkują książki techniczne, więc doceniam, gdy ktoś czyta rozdziały książki we właściwej kolejności. Jednakże może się też zdarzyć, że ktoś czyta tę książkę od tyłu. W takim przypadku omówienie aplikacji Hello World! z tego rozdziału może być odświeżająco prostym przykładem budowania aplikacji Silverlight bez obciążenia wzorcami, takimi jak Model View ViewModel (MVVM), nazwami, takimi jak DependencyProperty, i technologiami, takimi jak usługi Windows Communication Foundation (WCF) Rich Internet Application (RIA) Services. Pozostali mogą się nie martwić omówimy wszystkie te elementy w dalszych częściach tej książki stopniowo rozwijając po drodze swoje umiejętności programowania w Silverlight. Sięgając po książkę na temat Silverlight dobrze byłoby wiedzieć, czym jest ta technologia. Na szczęście kiepsko u mnie z marketingiem, więc ujmę to prosto: Silverlight jest wieloplatformowym środowiskiem uruchomieniowym.net, wtyczką dla różnych przeglądarek i zbiorem narzędzi projektowych opartych na systemie Windows przeznaczonym do budowania
4 Rozdział 1 Wprowadzenie do Silverlight złożonych aplikacji internetowych. Silverlight jest w istocie implementacją pojęć i standardów znanych z Windows Presentation Foundation (WPF), takich jak wiązanie, system właściwości i język znaczników XAML (Extensible Application Markup Language) w wersji środowiska uruchomieniowego CLR (Common Language Runtime) i bibliotek dla wielu platform. To wszystko. Myślę, że w tym akapicie udało mi się zdefiniować wszystkie skrótowce używane na pozostałych stronach tej książki. Jest to jednak technologia firmy Microsoft, więc można spodziewać się po drodze dalszych skrótowców. Technologia Silverlight działa na platformach Windows i Mac, a także na platformie Linux poprzez projekt Moonlight. Działa też na telefonach Windows Phone 7 i Nokia Symbian S60. Widzieliśmy demonstracje jej działania na konsolach podłączanych do telewizorów oraz obsługiwanie przez nią reklam i treści na konsoli Xbox. Podsumowując, poza ASP.NET, Silverlight jest najszerzej dostępną technologią wyprodukowaną przez Microsoft. Aplikacje Silverlight działają w sieci WWW, a także na komputerach klienckich. Możemy tworzyć niemal dowolne typy aplikacji w Silverlight, od serwisów WWW, do gadżetów, odtwarzaczy multimediów i rozbudowanych aplikacji klienckich. W tej części przedstawimy technologię Silverlight, przyglądając się, jak pasuje ona do zestawu narzędzi projektowych dostępnych dla sieci WWW i pulpitu. Następnie przyjrzymy się kilku różnym typom aplikacji Silverlight, do których Silverlight dobrze się nadaje. Następnie wypróbujemy funkcje i możliwości, które zostały dodane od czasu pierwszego wydania tej książki, a wreszcie podsumujemy przykładem tworzenia pierwszej aplikacji Silverlight. Technologia Silverlight rozpoczęła swoje działanie jako wtyczka dla stron WWW, od tego też zaczniemy w tej książce. 1.1 Silverlight i sieć WWW Silverlight zajmuje ciekawe miejsce pomiędzy aplikacjami dla pulpitu i aplikacjami dla przeglądarki. W pewnym sensie jest jak tradycyjna aplikacja dla pulpitu wbudowana w HTML. Oczywiście to samo można powiedzieć o wielu aplikacjach JavaScript Ajax, które same opierają się na modelu aplikacji dla pulpitu z kodem po stronie klienta. Świetne biblioteki, takie jak jquery, i nadchodząca, nieco mgliście zdefiniowana, wersja HTML 5, trochę zaciemniają obraz. Jakie jest miejsce technologii Silverlight w sieci WWW? Dlaczego mielibyśmy korzystać z Silverlight zamiast z tych innych technologii? Podam kilka powodów: Technologia Silverlight jest już dostępna. Silverlight działa już na wielu platformach i w wielu przeglądarkach. Silverlight zawiera obsługę multimediów na najwyższym poziomie, w tym znacznie bardziej zaawansowane zarządzanie prawami cyfrowymi (DRM), niż proponowane standardy HTML 5. Silverlight jest prostą technologią, jeśli ktoś jest już programistą.net szukającym dostępu do innych platform.
Silverlight i WPF 5 Nie należy mnie źle rozumieć; sądzę, że wersja HTML 5, gdy zostanie w pełni opisana i przyjęta, będzie świetnym elementem sieci WWW zarówno ekscytującym, jak i kryjącym wiele możliwości. To powiedziawszy, technologia Silverlight oferuje bardziej zaawansowane narzędzia autorskie, szybsze działanie i więcej możliwości, niż kiedykolwiek będzie się można spodziewać po HTML 5. Zamiast prowadzić grę o sumie zerowej, sądzę, że HTML 5 podniesie poprzeczkę zwiększając jakość i możliwości szerokiego spektrum platform i narzędzi programistycznych. Osobiście nie uważam, że zniknie podejście do tworzenia aplikacji z kodem po stronie klienta. Chociaż przez lata wieszczono koniec wielu ważnym podejściom programistycznym, to kilka z nich faktycznie upadło, podczas gdy popularność innych rosła. Technologie Silverlight i HTML 5 po prostu zapewnią więcej opcji implementowania potrzebnych rozwiązań w najbardziej optymalny sposób, przy użyciu znajomych narzędzi i już nabytych umiejętności. Warto też pamiętać, że technologie HTML/JavaScript oraz Silverlight nie wykluczają się wzajemnie. Aplikacje Silverlight mogą spokojnie współistnieć na stronie z aplikacjami Ajax wzajemnie się uzupełniając poprzez jak najlepsze wykorzystanie swoich mocnych stron. Silverlight to znacznie więcej niż technologia internetowa. Chociaż aplikacje Silverlight mogą działać na stronie WWW, to często też istnieją aplikacje Silverlight działające poza przeglądarką albo połączone z usługami, albo po prostu wykorzystujące zasoby klienta. W tych przypadkach można zastanawiać się, kiedy skorzystać z WPF, a kiedy z Silverlight. 1.2 Silverlight i WPF Technologie Silverlight i WPF zrodziły się z tych samych pomysłów. Technologia WPF pojawiła się najpierw i przyczyniła się do uczynienia z XAML języka znaczników przyjaznego przy tworzeniu interfejsów użytkownika. Wprowadziła też pojęcia właściwości zależnościowych i wiązań, animacji opartej na scenariuszach oraz interfejsów użytkownika rysowanych wektorowo z dokładnością do fragmentów pikseli. Technologia WPF jest jednak rozbudowana i skomplikowana. Jest też głęboko zakorzeniona w systemie Windows bez dobrych sposobów na wykorzystanie innych platform niż te, na których się opiera. Wykorzystuje też przy zabezpieczaniu aplikacji nieco przestarzały i nieprzyjazny dla WWW model zabezpieczeń dostępu z poziomu kodu. Gdy więc firma Microsoft zdecydowała się wejść w dziedzinę rozbudowanych aplikacji internetowych z technologią wektorowych interfejsów użytkownika opartą na CLR, wzięła pomysły i część kodu z technologii WPF i zaimplementowała je ponownie w bardziej zwarty i niezależny od platformy sposób. Silverlight jest w znacznej mierze podzbiorem technologii WPF z kilkoma dodatkami. Niektóre z tych dodatków, takie jak Visual State Manager, zostały następnie przeniesione z powrotem z Silverlight do WPF. Inne, takie jak Deep Zoom, Media Stream Source oraz interfejsy API do obsługi kamer internetowych i mikrofonów są obecnie funkcjami obecnymi jedynie w Silverlight. Pomijając alternatywne rozwiązania tych samych problemów, rysunek 1.1 pokazuje tę relację korzystając z diagramu Venna.
6 Rozdział 1 Wprowadzenie do Silverlight WPF Silverlight Rysunek 1.1 Silverlight jest przede wszystkim podzbiorem WPF z kilkoma dodanymi elementami. Pomijając alternatywne rozwiązania tych samych problemów, miejscami, gdzie WPF różni się najbardziej, są integracja z systemem operacyjnym Windows i dostęp do pełnej platformy.net. Sugeruję, aby programiści, którzy nie znają żadnej z tych technologii, zapoznali się najpierw z Silverlight przed zaznajomieniem się z WPF. Ogólnie rzecz biorąc łatwiej będzie się najpierw nauczyć technologii Silverlight, a następnie przejść do WPF, jeśli będzie taka potrzeba. Silverlight ma mniejszy zakres, zwykle ma jedno podejście do rozwiązania danego problemu, natomiast WPF może mieć kilka rozwiązań dla tego samego zadania. Chociaż Silverlight nie zawiera wszystkiego tego co WPF, to jest świetną, sprawną platformą programistyczną, którą można wykorzystać do wielu typów aplikacji, które wcześniej pisalibyśmy przy użyciu technologii Windows Forms, WPF lub nawet HTML. 1.3 Typy aplikacji Silverlight Możemy zbudować niemal dowolną aplikację korzystając z Silverlight. Oczywiście Silverlight do niektórych typów aplikacji bardziej się nadaje niż do innych. Na przykład, choć to możliwe, raczej nie będziemy chcieli zbudować całego serwisu WWW przy użyciu Silverlight; do tego zadania są lepsze narzędzia. Silverlight świetnie nadaje się do multimediów. Gdy pojawiła się wersja Silverlight 1.0, jedną z pierwszych jej możliwości była doskonała obsługa multimediów. W kolejnych wersjach aż do 4 technologia Silverlight rozbudowywała tę obsługę o nowe możliwości multimedialne, takie jak płynne przetwarzanie strumieniowe, dołączane kodeki wykorzystujące interfejs Media Stream Source API, a nawet technologie DRM wymagane przez dużych producentów treści multimedialnych chcących wykorzystać Silverlight. Skupienie się przez Silverlight od samego początku na multimediach było zarówno pomocne, jak i bolesne. Wideo w sieci WWW jest świetnym sposobem na upowszechnienie produktu zwłaszcza, gdy mamy wydajną technologię wideo wysokiej rozdzielczości. Na wczesnym etapie wielu potencjalnych programistów Silverlight nie wykraczało poza możliwości multimedialne Silverlight i nie dostrzegało bogatych możliwości biznesowych oferowanych przez tę technologię. W wersjach 3 i 4 technologia Silverlight zyskała poważne możliwości biznesowe. Od najprostszych rzeczy, takich jak synchroniczne i asynchroniczne sprawdzanie poprawności, po wzorce, takie jak MVVM i Prism oraz całe platformy obsługujące warstwę pośrednią aplikacji, takie jak usługi WCF RIA Services, technologia Silverlight zaprezentowała się jako dojrzała platforma będąca w stanie przystosować się do najlepszych praktyk i je rozwijać. Chociaż aplikacje biznesowe i multimedialne są świetnymi przykładami, to innym ciekawym typem aplikacji są gry. Silverlight ma dobre wsparcie do tworzenia lekkich gier, w tym możliwość generowania bitmap na bieżąco, tworzenia dźwięków, zapętlania muzyki odtwarzanej
Co nowego pojawiło się od pierwszego wydania 7 w tle i wiele więcej. Społeczność programistów z powodzeniem przeniosła do Silverlight istniejące silniki wspomagające prawa fizyki i programowanie gier, jeszcze bardziej ułatwiając tworzenie bardziej rozbudowanych gier. Przyszłe wersje Silverlight mają być nieporównywalnie bardziej przyjazne tworzeniu gier; na razie widać tylko wierzchołek góry lodowej. Istnieje wiele innych typów aplikacji Silverlight, począwszy od reklam, przeglądarek zdjęć, klientów serwisów społecznościowych, aż do odpowiedników niemal każdego rodzaju aplikacji pulpitowych i internetowych. Niektóre z nich nie były możliwe do stworzenia w wersji Silverlight 2, która była wykorzystywana w pierwszym wydaniu tej książki. Przyjrzyjmy się ogólnie, co się zmieniło w tym czasie. 1.4 Co nowego pojawiło się od pierwszego wydania Pierwsze wydanie książki było napisane dla wersji Silverlight 2. Wersje Silverlight 3 i 4 dodały tej platformie zadziwiającą liczbę nowych możliwości we wszystkich obszarach od funkcji podstawowych, przez obsługę urządzeń, aż do wprowadzenia zarówno zaufanych, jak i ograniczonych aplikacji klienckich działających poza przeglądarką. Nowości w Silverlight można luźno pogrupować na cztery główne obszary: aplikacje biznesowe i klienckie, multimedia i grafika, interakcja z użytkownikiem oraz tekst. 1.4.1 Funkcje dla aplikacji biznesowych i klienckich Gdy ukazało się pierwsze wydanie tej książki, wersja Silverlight 2 dopiero zaczynała zdobywać uznanie. Była to całkiem nowa technologia firmy Microsoft (w każdym razie, jeśli chodzi o wersję z kodem zarządzanym) mająca silną konkurencję. Chociaż wersję Silverlight 2 można było stosować do budowania bogatych aplikacji biznesowych, to nie miała jeszcze takich atutów, aby stać się silnym konkurentem w tym obszarze. Wiele funkcji z tego działu przydaje się w aplikacjach różnych rodzajów; nie lubię klasyfikować ich pod nagłówkiem biznesowe, ale są one najczęściej wykorzystywane w aplikacjach tego rodzaju. Sprawdzanie poprawności omówione w rozdziale 13 było jedną z najważniejszych, nowych funkcji dla aplikacji biznesowych. Technologia Silverlight nie tylko dodała sprawdzanie poprawności, ale dołączyła też obsługę sprawdzania poprawności poprzez atrybuty, przez wyjątki, a nawet asynchroniczną, przy czym wszystkie te rodzaje współpracują z kontrolkami Silverlight. Technologia Silverlight umożliwiła nawet całkowite dostosowywanie stylu prezentowanej użytkownikom końcowym informacji o błędach związanych ze sprawdzaniem poprawności. Jedną z technologii, która w dużym stopniu korzysta z funkcji sprawdzania poprawności, są usługi WCF RIA Services (rozdział 17). Znaczna część funkcjonalności związanej ze sprawdzaniem poprawności, która została wprowadzona do środowiska uruchomieniowego Silverlight, pochodzi w istocie z tego projektu. Usługi WCF RIA Services zapewniają sposób na udostępnianie sprawdzania poprawności i logiki działania pomiędzy klientem i serwerem, a także platformę do sprawdzania poprawności, dostępu do danych i zabezpieczeń, którą można wykorzystywać wspólnie w aplikacjach Silverlight i innych klientach.
8 Rozdział 1 Wprowadzenie do Silverlight Usługi WCF RIA Services opierają się na technologii WCF, ale nie jest to ich jedyne usprawnienie. Stos sieciowy technologii Silverlight, opisany w rozdziale 14, został w znacznym stopniu usprawniony tak, aby obsługiwał działanie w ramach przeglądarki oraz poza przeglądarką, a także protokół SOAP 1.2 i wiele nowych ulepszeń protokołów. Zmiany te ułatwiły korzystanie z Silverlight za zaporami internetowymi, gdzie usługi mają często inne wymagania niż te, które działają w Internecie. Mimo obietnic biura bez papieru, drukowanie (omówione w rozdziale 19) jest nadal ważną funkcją wszystkich aplikacji biznesowych. Drukowanie w Silverlight zoptymalizowano do tworzenia raczej krótkich raportów lub dokumentów, a także operacji odpowiadających tworzeniu zrzutów ekranowych. Jest niezwykle proste w użyciu tak proste, jak praca z językiem XAML na stronach aplikacji. Wreszcie dochodzimy do zmiany najważniejszej: ograniczonych i zaufanych aplikacji działających poza przeglądarką. Omówiony w podrozdziale 5.1 tryb działania poza przeglądarką był jednym z najważniejszych usprawnień sposobu działania aplikacji Silverlight. Wersja Silverlight 3 wprowadziła podstawowy tryb działania poza przeglądarką z ograniczeniami odpowiadającymi z grubsza tym, które obowiązują w przeglądarce. Wersja Silverlight 4 umożliwiła tworzenie całkiem nowych klas aplikacji dodając zaufany tryb aplikacji z ograniczoną liczbą komunikatów ostrzegawczych, zwiększonym dostępem do plików i dostępem do serwerów IDispatch COM Automation (w systemie Windows). Wszystkie te funkcje składają się na platformę, która świetnie nadaje się do tworzenia klientów dla skomplikowanych aplikacji biznesowych. Jednym z kolejnych głównych obszarów usprawnień w Silverlight są multimedia. 1.4.2 Usprawnienia multimediów i grafiki Technologia Silverlight od początku była najlepiej znana ze swoich możliwości multimedialnych. Zespół zajmujący się multimediami w Silverlight nie poprzestał na tym, znacząco rozbudowując możliwości multimedialne w wersjach Silverlight 3 i 4. Wersja Silverlight 2 zawierała interfejs Media Stream Source API do przekazywania multimediów przez sieć. Ten interfejs programistyczny wymagał jednak, aby przekazywane bity były wstępnie zakodowane w jednym z formatów bezpośrednio wówczas obsługiwanych. Chociaż było to użyteczne, mogło prowadzić do podwójnego kodowania i sprawiało, że przekodowywanie stawało się jeszcze trudniejsze. Wersja Silverlight 3 dodała obsługę przekazywania nieprzetworzonego obrazu i dźwięku z niestandardowych implementacji interfejsu Media Stream Source, jak to zostało omówione w podrozdziale 20.6. W efekcie możemy napisać zarządzany kodek dla dowolnego typu mediów lub nawet zrobić coś tak szalonego, jak to, co sam zrobiłem i wykorzystać tę funkcję do generowania dźwięku i wideo w czasie rzeczywistym na potrzeby emulatora. Inną opcją generowania wideo lub obrazów w czasie rzeczywistym jest nowy interfejs programowania bitmap omówiony w podrozdziale 21.2. Mówiąc o kodekach, jednym z nowo dodanych kodeków był H.264 do obsługi wideo. H.264 stał się jednym z najpopularniejszych kodeków dla obrazu telewizyjnego i wideo obsługiwanym przez różne urządzenia. Stał się logicznym wyborem jako dodatkowy format
Co nowego pojawiło się od pierwszego wydania 9 wbudowany w Silverlight, ponieważ teraz producenci treści multimedialnych mogą wykorzystywać jeszcze więcej swoich materiałów bez przekodowywania. Co istotne dla tych samych odbiorców, wersje Silverlight 3 i 4 jeszcze bardziej usprawniły możliwości DRM, włącznie z dodaniem obsługi DRM przy braku łączności z siecią. Nową, ekscytującą funkcją Silverlight 4 jest wbudowana obsługa urządzeń do przechwytywania wideo i audio, a w szczególności kamer internetowych i mikrofonów. Obsługa ta otwiera wiele nowych możliwości tworzenia aplikacji, chociaż nie osiągnęła jeszcze poziomu pozwalającego nam tworzyć aplikacje do rozmów wideo w czasie rzeczywistym. Obsługa kamer internetowych i mikrofonów została omówiona w podrozdziale 20.7. Wewnętrznie Silverlight obsługuje teraz wszystkie formaty graficzne PNG, które w poprzednich wersjach były obsługiwane tylko częściowo. Silverlight 4 ma również obsługę procedur cieniowania pikseli (pixel shader) i zestaw wbudowanych efektów zoptymalizowanych pod względem wydajności, takich jak cienie i rozmycie( podrozdział 18.4). Przy wszystkich tych usprawnieniach oraz wielu optymalizacjach wydajności, a nawet dodatkach, takich jak Silverlight Media Framework, technologia Silverlight nadal jest liderem w obszarze multimediów oferując wszystko co potrzebne do tworzenia rozbudowanych aplikacji skupiających się na multimediach. Czasami chcemy czegoś więcej niż tylko efektów multimedialnych; chcemy aplikacji, które mogą być naprawdę interaktywne. Silverlight również tutaj ma coś do zaoferowania. 1.4.3 Interakcja z użytkownikiem Od wersji Silverlight 2 interakcja z użytkownikiem doczekała się wielu ważnych usprawnień. Dwie najbardziej pożądane funkcje, obsługa kółka myszy i klikania prawym przyciskiem myszy (co zostało omówione w podrozdziale 8.2), są teraz wbudowane w podstawowe środowisko uruchomieniowe Silverlight. Jednym z nowszych i najbardziej interesujących mechanizmów interakcji z użytkownikiem jest wielodotyk omówiony w podrozdziale 8.3. Możliwość obsługi wielopunktowej interakcji z interfejsem użytkownika, zwłaszcza w scenariuszach wykorzystujących kioski multimedialne i urządzenia podręczne, szybko staje się wymaganiem dla wielu aplikacji. Silverlight zawiera teraz w aplikacjach obsługę wielopunktowej interakcji dotykowej na poziomie podstawowego środowiska rozruchowego. Innym elementem interakcji z użytkownikiem, którego brakowało w Silverlight 2, jest łatwa możliwość wyświetlania okien dialogowych i (symulowanych) wyskakujących okien w aplikacjach. Silverlight teraz obsługuje nie tylko te elementy (co omówiono w rozdziale 15), ale też wyskakujące powiadomienia omówione w rozdziale 5. Cała interakcja na świecie nie jest nic warta, jeśli użytkownik nie może przeczytać tekstu na ekranie. Na szczęście Silverlight zawiera również usprawnienia w dziedzinie tekstu. 1.4.4 Tekst Zdecydowanie największym usprawnieniem dotyczącym tekstu od wersji Silverlight 2 jest poprawne obrazowanie czcionek ClearType. Wersja Silverlight 2 przeprowadzała jedynie
10 Rozdział 1 Wprowadzenie do Silverlight obrazowanie z użyciem odcieni szarości, co sprawiało, że tekst miał nieco rozmazany wygląd, o ile starannie nie wybraliśmy schematów kolorystycznych. Podczas gdy obsługa ClearType może być ważna dla obrazowania czcionek w ogóle, to tekst czytany od prawej do lewej lub dwukierunkowy jest czymś, co jest całkowicie niezbędne dla prawidłowego obrazowania wielu języków pozaeuropejskich. Silverlight obsługuje nie tylko tekst dwukierunkowy, ale też edytory metod wprowadzania tekstu (IME) dla skomplikowanych znaków złożonych stosowanych w wielu językach, zwłaszcza dalekowschodnich. Znaczącym usprawnieniem obrazowania i wprowadzania tekstu jest pojawienie się nowej kontrolki formatowanego pola tekstowego. Ta kontrolka pozwala nam wyświetlać lub edytować tekst, który zawiera wiele czcionek i stylów. W tej kontrolce mogą być nawet osadzane inne elementy, które mogą być interaktywne, gdy kontrolka jest w trybie tylko do odczytu. ClearType, tekst dwukierunkowy, edytory wprowadzania tekstu i formatowane pole tekstowe omówiono w rozdziale 9 razem z przedstawieniem procesu obrazowania tekstu i sposobami zastosowania tych nowych funkcji w Silverlight. To tylko główne elementy. Oczywiście jest jeszcze wiele innych usprawnień. Oprócz omówienia w tej książce elementów podstawowych, dodałem też informacje oparte na swoim doświadczeniu, uzyskane w pracy z Silverlight od momentu wprowadzenia tej technologii, jak również na swojej najnowszej wiedzy zdobytej w bliskiej współpracy z zespołem produktowym Silverlight. Ważniejsze sprawy, takie jak układ elementów i obrazowanie, potraktowałem głębiej, aby uzyskać wgląd w wewnętrzne działanie Silverlight. Daje to bardzo duży zakres materiału. Mam nadzieję, że wszystkim będzie się to tak dobrze czytać, jak dobrze mi się to pisało. Zanim zaczniemy omawiać obszary związane z poszczególnymi funkcjami, będziemy musieli przygotować swoje środowisko programistyczne i zbudować niewielką aplikację Hello World!. 1.5 Rozpoczęcie programowania w Silverlight Kto już jest programistą.net, ten jest na dobrej drodze do stania się programistą Silverlight. Silverlight opiera się na platformie.net i wykorzystuje te same narzędzia, co inne aplikacje platformy.net. Do budowania swoich aplikacji będziemy wykorzystywać Visual Studio i opcjonalnie Expression Blend. Przykładowy kod do wykorzystania można znaleźć w CodePlex i innych serwisach z otwartym kodem. Oczywiście będziemy też mogli skorzystać ze wsparcia ogromnej społeczności programistów podczas rozwiązywania trudnych problemów. Zanim jednak do tego przejdziemy, musimy zająć się instalacją swojego środowiska programistycznego. 1.5.1 Instalowanie środowiska programistycznego Silverlight 4 wymaga Visual Studio 2010 do pracy z projektami i budowania rozwiązań. Obsługa wielu platform docelowych w Visual Studio 2010 oznacza, że nasze aplikacje mogą być budowane dla wersji Silverlight 3 lub Silverlight 4, gdy mamy zainstalowane narzędzia Silverlight 4.
Rozpoczęcie programowania w Silverlight 11 Kto nie ma jeszcze zainstalowanej wersji Visual Studio 2010, może pobrać darmowe oprogramowanie Visual Web Developer 2010 Express z serwisu Microsoft pod adresem www. microsoft.com/express/web/. To darmowe narzędzie do programowania aplikacji internetowych pozwoli nam tworzyć aplikacje Silverlight 4, jak również aplikacje ASP.NET. Kto chce korzystać z dodatkowych funkcji i narzędzi oraz możliwości tworzenia nie tylko aplikacji internetowych, powinien zainstalować co najmniej wersję Visual Studio 2010 Pro. Po zainstalowaniu Visual Studio 2010 należy odwiedzić adres http://silverlight.net/getstarted/ i skorzystać z narzędzia Web Platform Installer, aby zainstalować oprogramowanie Silverlight 4 Tools i pakiet SDK, a także ewentualne składniki opcjonalne. Narzędzia Silverlight Tools for Visual Studio 2010 oraz pakiet SDK zawierają wszystko, co potrzeba do programowania aplikacji Silverlight 4, w tym usługi WCF RIA Services 1.0. Opcjonalnie można zainstalować Microsoft Expression Blend 4. Łącze do tego oprogramowania jest też dostępne na stronie Get Started witryny Silverlight.net. Program Expression Blend 4 zapewnia zestaw narzędzi przyjaznych dla projektantów, które ułatwiają tworzenie skomplikowanych animacji, zachowań i układów elementów. Firma Microsoft i społeczność programistów stworzyły wiele przydatnych witryn internetowych, które mogą być pomocne w procesie uczenia. 1.5.2 Przydatne witryny Oficjalną witryną programistów Microsoft Silverlight jest http://silverlight.net. Znaleźć tam można filmy wideo, przykładowe aplikacje, podręczniki, dodatki i fora społecznościowe pomagające zostać jak najlepszym i najskuteczniejszym programistą Silverlight. Oprócz Silverlight.net, witryna http://channel9.msdn.com zawiera wywiady z członkami społeczności i zespołu produktowego oraz samouczki. Program Silverlight.TV, dostępny na witrynie Channel 9 pod adresem http://channel9.msdn.com/shows/silverlighttv/, jest świetnym źródłem aktualnych informacji na tematy związane z Silverlight. Dokumentację MSDN dla Silverlight 4 można znaleźć pod adresem http://bit.ly/ SL4MSDN. Nieskromnie polecę też subskrypcję swojego bloga dostępnego pod adresem http://10rem. net. Jestem też dostępny w sieci twitter; mój identyfikator to @pete_brown. Jeszcze jednym miejscem wartym odwiedzin jest serwis Silverlight Cream prowadzony przez Dave a Campbella pod adresem http://bit.ly/silverlightcream. Dave wykonuje znakomitą robotę codziennie zbierając najlepsze wpisy na temat Silverlight z sieci WWW. Z bloga Dave a można się zorientować, które blogi innych członków społeczności warto subskrybować. W tym momencie mamy skonfigurowany komputer, subskrypcję kilku blogów, utworzone konto w serwisie Silverlight.net, a może nawet odwiedzone kilka witryn dotyczących Silverlight. Zanim szczegółowo zajmiemy się różnymi funkcjami w dalszych częściach książki, myślę, że dobrze byłoby zobaczyć, jak łatwo jest zbudować pierwszą aplikację w Silverlight.
12 Rozdział 1 Wprowadzenie do Silverlight 1.6 Budowa pierwszej aplikacji internetowej w Silverlight Oczekiwania znacznie wzrosły od czasów języka C, gdy samo skompilowanie programu wypisującego tekst Hello World! na ekranie było traktowane jako spore osiągnięcie. Zamiast przerabiać ten wyświechtany przykład, myślę, że byłoby nieźle, gdyby nasz przykładowy program Hello World! w istocie robił coś ciekawego jak na przykład korzystał z publicznej usługi w sieci WWW. Twitter jest wszechobecnym przykładem, więc nie będę wyłamywał się z tego trendu. Wykorzystanie w tym przykładzie serwisu Twitter a w szczególności wyszukiwania w serwisie Twitter pozwoli nam też poznać kilka funkcji Silverlight, w tym układ elementów, dostęp do sieci, technologię LINQ to XML i inne. 1.6.1 Przygotowanie projektu Otwórzmy Visual Studio 2010. Wybierzmy File > New Project i utwórzmy nowy projekt Silverlight Application. Nazwa nie jest istotna, ale ja dla swojego projektu wybrałem First- SilverlightApplication. Rysunek 1.2 pokazuje to okno dialogowe z ustawionym odpowiednim typem i nazwą projektu. Po kliknięciu OK pojawi się kolejne okno dialogowe, udostępniające opcje specyficzne dla projektu aplikacji Silverlight. Rysunek 1.3 przedstawia to okno dialogowe. Rysunek 1.2 projektu Okno dialogowe New Project w Visual Studio 2010 z ustawionym odpowiednim typem i nazwą
Budowa pierwszej aplikacji internetowej w Silverlight 13 Rysunek 1.3 Okno dialogowe New Silverlight Application Zwykle można zostawić domyślne wartości opcji w tym oknie dialogowym i po prostu kliknąć OK. Ważne jest jednak, aby zrozumieć dostępne opcje. Tabela 1.1 opisuje każdą z opcji przedstawionych w tym oknie dialogowym. Tabela 1.1 Opcje okna dialogowego New Silverlight Application Opcja Host the Silverlight application in a new website (Utrzymuj aplikację Silverlight w nowej witrynie WWW) New Web Project Name (Nazwa nowego projektu WWW) New Web Project Type (Typ nowego projektu WWW) Silverlight Version (Wersja Silverlight) Enable WCF RIA Services (Włącz usługi WCF RIA Services) Opis Aplikacje Silverlight, nawet aplikacje działające poza przeglądarką, są uruchamiane z poziomu witryny WWW. Można je również uruchamiać ze statycznej strony HTML w systemie plików. Zwykle warto pozostawić tę opcję zaznaczoną, chyba że mamy istniejącą witrynę WWW, którą chcemy wykorzystać podczas budowania aplikacji. Tutaj należy podać nazwę projektu witryny WWW. Domyślna nazwa jest zwykle wystarczająca. Będąc programistą ASP.NET i mając jakieś preferencje odnośnie typu projektu ASP.NET, można go tu ustawić. W przeciwnym razie należy zostawić opcję domyślną. Ta opcja pozwala nam wybrać wersję Silverlight 3 albo Silverlight 4. W każdym przykładzie w tej książce będziemy zakładać wybór wersji Silverlight 4. To pole należy zaznaczyć, jeśli chcemy podłączyć projekt WWW do projektu Silverlight jako punkt końcowy usług WCF RIA Services. To włączy dodatkowe narzędzia dostępne podczas kompilacji. Po utworzeniu nowego rozwiązania zobaczymy dwa projekty. Pierwszy jest aplikacją Silverlight, drugi jest witryną WWW. Projekt witryny WWW zawiera folder ClientBin, który będzie zawierał skompilowany plik wynikowy (plik.xap) naszej aplikacji Silverlight. Zawiera też dwie strony testowe, które można wykorzystywać do testowania aplikacji Silverlight. Domyślnie
14 Rozdział 1 Wprowadzenie do Silverlight strona.aspx jest ustawiona jako strona startowa, ale możemy też skorzystać ze strony HTML, jeśli później planujemy udostępniać ją na serwerze nie obsługującym.net (tak, aplikacje Silverlight mogą być obsługiwane przez dowolny serwer HTTP, a nie tylko usługi Internet Information Services [IIS] wykorzystujące ASP.NET). Gdy projekt jest otwarty i gotowy, czas przejść do interfejsu użytkownika. 1.6.2 Interfejs użytkownika Otwórzmy plik MainPage.xaml; jest on zwykle otwarty domyślnie po utworzeniu nowego projektu Silverlight. MainPage.xaml jest stroną startową naszej aplikacji, co zostało ustawione przez pojedynczy wiersz kodu w pliku App.xaml.cs. Pomiędzy otwierającym a zamykającym znacznikiem Grid dodajmy następujący kod XAML: <Button Content="Get Tweets" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" x:name="gettweets" VerticalAlignment="Top" Width="75"/> <ListBox x:name="tweetlist" Margin="12,41,12,12"/> Ten kod tworzy dwa elementy na stronie: element Button (przycisk) i element ListBox (pole listy). Moglibyśmy przeciągnąć te kontrolki z pola narzędzi (toolbox) na obszar projektu, ale trudno byłoby to opisać szczegółowo w książce. W widoku projektu powinniśmy uzyskać formularz podobny do pokazanego na rysunku 1.4. Następnie możemy podwójnie kliknąć przycisk Get Tweets, aby utworzyć procedurę obsługi zdarzenia w kodzie. Kod ten, podobnie jak pozostały kod aplikacji Silverlight, będzie uruchamiany po stronie klienta wewnątrz wtyczki Silverlight. Procedura obsługi zdarzenia zostanie użyta w następnym przykładzie, gdzie wywołamy interfejs API wyszukiwania w serwisie Twitter.
Budowa pierwszej aplikacji internetowej w Silverlight 15 Rysunek 1.4 Środowisko programistyczne Visual Studio 2010 przedstawiające prawidłowo wprowadzony kod dla MainPage.xaml 1.6.3 Wywoływanie wyszukiwania w serwisie Twitter Następnym krokiem jest wywołanie interfejsu wyszukiwania w serwisie Twitter. Uzupełnijmy procedurę obsługi zdarzenia, którą właśnie utworzyliśmy w kodzie, aby zawierała następujący kod: private void GetTweets_Click(object sender, RoutedEventArgs e) { WebClient client = new WebClient(); } client.downloadstringcompleted += (s,ea) => { System.Diagnostics.Debug.WriteLine(ea.Result); }; client.downloadstringasync( new Uri("http://search.twitter.com/search.atom?q=silverlight")); Ten kod robi kilka ciekawych rzeczy. Po pierwsze tworzy wystąpienie klasy WebClient, jednego z najłatwiejszych w użyciu klientów sieciowych w Silverlight. Następnie konfiguruje
16 Rozdział 1 Wprowadzenie do Silverlight procedurę obsługi zdarzenia korzystając z wyrażenia lambda, aby reagować na otrzymane wyniki. Na koniec asynchronicznie wywołuje metodę pobierającą łańcuch wyników z serwisu search.twitter.com. Wyszukiwanie dotyczy wpisów zawierających silverlight. WSKAZÓWKA Podejście z wyrażeniem lambda wykorzystuje tutaj po prostu anonimowego delegata (funkcję bez nazwy) jako procedurę obsługi zdarzenia. Piękno tego podejścia polega na tym, że nie zaśmieca ono kodu wieloma procedurami obsługi zdarzeń, które w istocie są częścią dyskretnych procesów. Więcej na temat wyrażeń lambda w języku C# można dowiedzieć się w serwisie MSDN pod adresem http://bit.ly/csharplambda. Wywołanie sieciowe jest asynchroniczne, ponieważ wszystkie wywołania sieciowe w Silverlight są asynchroniczne. Może to początkowo wymagać nieco przyzwyczajenia, ale po kilku przykładach łatwo sobie z tym poradzić. Rozdział 14 szczegółowo opisuje, jak korzystać z metod asynchronicznych, a także jakie są tego powody. Jeśli uruchomimy aplikację, możemy kliknąć przycisk Get Tweets i przejrzeć okno wyników. Zobaczymy, że już zbudowaliśmy wystarczająco dużo, aby wywoływać interfejs serwisu Twitter i pobierać wyniki w formacie XML. Nieźle, jak na kilka wierszy kodu! Naszym następnym kodem jest przetworzenie wyników i wyświetlenie ich w kontrolce ListBox. 1.6.4 Przetwarzanie wyników i wiązanie z kontrolką ListBox Jeśli zajrzymy do okna wynikowego z ostatniego uruchomienia programu, to zobaczymy, że formatem wynikowym jest dokument AtomPub z węzłem entry dla każdego z wyników. W Silverlight możemy przetwarzać format Atom na kilka sposobów: możemy skorzystać z przetwarzania wbudowanego w klasę SyndicationFeed albo możemy skorzystać z technologii LINQ to XML do przetworzenia wyników. LINQ to XML jest świetną technologią i ma wiele zastosowań poza przetwarzaniem dokumentów AtomPub, więc pójdę tutaj tą trasą. Otrzymamy w ten sposób nieco więcej kodu niż przy podejściu alternatywnym, ale myślę, że jest to tego warte. Klasa Tweet Zanim przeprowadzimy samo przetwarzanie, będziemy musieli utworzyć prostą klasę do przechowywania wyników, które nas interesują. W Visual Studio kliknijmy prawym przyciskiem projekt Silverlight i wybierzmy Add > Class. Nazwijmy klasę Tweet.cs i wypełnijmy ją tak, aby wyglądała, jak poniżej: public class Tweet { public string Message { get; set; } public Uri Image { get; set; } }
Budowa pierwszej aplikacji internetowej w Silverlight 17 Zapiszmy tę klasę i przejdźmy z powrotem do MainPage.xaml.cs. Gdzieś wewnątrz klasy MainPage dodajmy następującą zmienną będącą kolekcją. Świetnym miejscem będzie wiersz nad metodą GetTweets_Click: private ObservableCollection<Tweet> _tweets = new ObservableCollection<Tweet>(); Kliknijmy prawym przyciskiem myszy nazwę typu ObservableCollection i wybierzmy Resolve, aby dodać odpowiednią instrukcję using do swojego kodu. Ta kolekcja będzie miejscem, gdzie umieścimy wszystkie przetworzone wpisy. Powiążemy też z nią kontrolkę ListBox. Z klasy ObservableCollection będziemy korzystać w rozdziale 11, gdy będziemy omawiać wiązanie. Przetwarzanie przy użyciu LINQ To XML LINQ jest technologią, z której wielu pewnie korzystało w innych projektach.net. Jeśli tak, to świetnie, ponieważ jest ona też obsługiwana w Silverlight. Jeśli nie, to łatwo sobie z nią poradzić. Można traktować ją prawie jak język SQL, ale osadzony w kodzie C#, działający na obiektach, zapisywany w odwrotnej kolejności i bez obecności bazy danych. No dobrze, nie jest to dokładny odpowiednik SQL, ale jest to świetny język zapytań, który pozwala nam wykonywać iteracje i filtrowania w pojedynczym wierszu kodu. W każdym razie nie trzeba być ekspertem od LINQ, aby zrozumieć ten przykład. Kliknijmy projekt prawym przyciskiem myszy i wybierzmy Add Reference; dodajmy odwołanie do System.Xml.Linq. Rysunek 1.5 pokazuje okno dialogowe z zaznaczonym prawidłowym odwołaniem. Rysunek 1.5 Okno dialogowe Add Reference z wybranym podzespołem System.Xml.Linq w celu skorzystania z funkcjonalności LINQ to XML
18 Rozdział 1 Wprowadzenie do Silverlight Po dodaniu odwołania zastąpmy instrukcję Debug.WriteLine i deklarację procedury obsługi zdarzenia w kodzie na kod z wydruku 1.1. Ten kod przeprowadza faktyczne przetwarzanie dokumentu XML zwracanego przez wyszukiwanie w serwisie Twitter i ładuje przetworzone wyniki do kolekcji tweets. Wydruk 1.1 Przetwarzanie wyników wyszukiwania w serwisie Twitter przy użyciu LINQ to XML client.downloadstringcompleted += (s, ea) => { XDocument doc = XDocument.Parse(ea.Result); XNamespace ns = "http://www.w3.org/2005/atom"; var items = from item in doc.descendants(ns + "entry") select new Tweet() { Message = item.element(ns + "title").value, Przestrzeń nazw Atom Image = new Uri(( from XElement xe in item.descendants(ns + "link") where xe.attribute("type").value == "image/png" select xe.attribute("href").value ).First<string>()), }; foreach (Tweet t in items) { _tweets.add(t); } }; Kliknijmy prawym przyciskiem myszy i ustalmy powiązanie klasy XDocument dodając prawidłową instrukcję using u góry swojego kodu. Ten kod przeprowadza ciekawe przetwarzanie. Najpierw ładuje wyniki do obiektu XDocument tak, żeby mogły być przetwarzane przy użyciu instrukcji LINQ. Następnie przechodzi przez cały dokument wybierając każdy element entry i tworząc z każdego nowy obiekt Tweet. Sam obiekt Tweet jest wypełniany poprzez pobranie najpierw wartości elementu title i przypisanie jej do właściwości Message, a następnie wykonanie innego zapytania LINQ w celu znalezienia elementu link, który ma typ image/png i przypisanie go do właściwości Image. Na koniec kod wykonuje to samo w pętli dla każdego z wyników i dodaje je do kolekcji tweets. Deklaracja przestrzeni nazw u góry jest konieczna, ponieważ przestrzeń nazw Atom jest domyślną przestrzenią nazw xmlns w dokumencie. Podczas przetwarzania XML musimy mieć zadeklarowaną domyślną przestrzeń nazw, w przeciwnym razie wyniki będą puste. Po poradzeniu sobie z przetwarzaniem, następnym krokiem jest powiązanie kontrolki ListBox z kolekcją _tweets, aby miała skąd czerpać dane.
Budowa pierwszej aplikacji internetowej w Silverlight 19 Wiązanie kontrolki ListBox Silverlight polega w dużej mierze na wiązaniu danych. Rozdział 11 szczegółowo opisuje, jak działa wiązanie i jak z niego korzystać. Na razie ważne jest, aby zrozumieć, że w Silverlight rzadko będziemy przypisywać dane bezpośrednio do kontrolek. Zamiast tego będziemy konfigurować wiązania i pozwalać elementom pobierać dane, gdy będą one dostępne. W tym przypadku chcemy ustawić właściwość ItemsSource kontrolki ListBox na naszą kolekcję tak, aby wiedziała, że ma załadować swoje poszczególne elementy z tej kolekcji, gdy zostanie ona zaktualizowana. Ponieważ korzystamy z obiektu ObservableCollection, kontrolka ListBox zostanie powiadomiona za każdym razem, gdy element zostanie dodany do tej kolekcji lub z niej usunięty. Dodajmy następujący wiersz kodu do konstruktora MainPage pod wywołaniem InitializeComponent: TweetList.ItemsSource = _tweets; To wszystko, co trzeba, aby skonfigurować wiązanie dla kontrolki ListBox. Uruchommy aplikację i pobierzmy wpisy. Powinien pojawić się wynik podobny do rysunku 1.6. Rysunek 1.6 Domyślne przedstawienie elementów kontrolki ListBox pozostawia wiele do życzenia. Wygląda to jak WinForms! Wymagam więcej od naszego pierwszego przykładu Silverlight. To jednak nie całkiem to, co chcieliśmy uzyskać. Widać tylko zbiór nazw typów. Chcemy wyświetlać obrazy i tekst. Widzimy nazwy typów, ponieważ jest to domyślne zachowanie szablonu elementów. Domyślnie poszczególne elementy są przedstawiane przez wynik wywołania metody ToString. To działa dobrze w przypadku łańcuchów tekstowych, liczb lub podobnych, prostych danych, ale niezbyt dobrze w przypadku skomplikowanych typów. Naszym końcowym krokiem w tym przykładzie jest poprawienie wyników kontrolki ListBox tak, abyśmy mogli zobaczyć coś bardziej znaczącego.
20 Rozdział 1 Wprowadzenie do Silverlight 1.6.5 Poprawianie zawartości kontrolki ListBox Aby kontrolka ListBox przedstawiała swoje elementy przy użyciu wybranego przez nas formatu, musimy skorzystać z szablonu DataTemplate. Szablony DataTemplate są szczegółowo omawiane w podrozdziale 11.4. Na razie wystarczy zrozumieć, że są fragmentami kodu XAML, które będą używane do sformatowania każdego elementu listy. Szablon DataTemplate dla tej kontrolki ListBox będzie zawierał dwie kolumny dla każdego wiersza. Pierwsza kolumna będzie zawierać obraz autora, a druga zawartość treści wpisu. Otwórzmy stronę MainPage.xaml i zastąpmy całą deklarację kontrolki ListBox kodem XAML z wydruku 1.2. Wydruk 1.2 Szablon DataTemplate do formatowania wpisów <ListBox x:name="tweetlist" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Margin="12,41,12,12"> <ListBox.ItemTemplate> <DataTemplate> <Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> DataTemplate zastosowany do każdego wystąpienia Tweet <Image Source="{Binding Image}" Grid.Column="0" Margin="3" Width="50" Height="50" Stretch="UniformToFill"/> <TextBlock Text="{Binding Message}" FontSize="14" Margin="3" Grid.Column="1" TextWrapping="Wrap" /> </Grid> </DataTemplate> </ListBox.ItemTemplate> </ListBox> W tym kodzie najpierw informujemy kontrolkę ListBox, że chcemy, aby jej zawartość zajmowała całą szerokość kontrolki ListBox bez żadnego przewijania w poziomie. Następny fragment kodu definiuje siatkę z automatycznie dopasowywanym rozmiarem pierwszej kolumny i drugą kolumną w pełnej szerokości. Następnie wiążemy element Image z właściwością Image klasy Tweet a element TextBlock z właściwością Message. Końcowy wynik wykonanej pracy, włącznie z tym szablonem DataTemplate dla kontrolki ListBox, pokazano na rysunku 1.7.
Podsumowanie 21 Rysunek 1.7 Końcowy efekt przykładu wyszukiwania w serwisie Twitter wygląda dobrze! Pracuję z Silverlight i WPF od wielu lat, ale nigdy nie przestało mnie zadziwiać to, jak łatwo jest mieć pełną kontrolę nad tym, co wyświetli aplikacja. Pamiętam dni, gdy musiałem kupować wyspecjalizowane kontrolki, wykonujące coś tak prostego, jak wyświetlanie obrazka wewnątrz pola listy. Teraz wystarcza tylko nieco kodu XAML. A jeśli ktoś nie lubi wpisywać kodu XAML, może otworzyć program Expression Blend i skorzystać z niego do interaktywnego zaprojektowania szablonu DataTemplate w oknie projektu. Jak kiedyś powiedział pewien słynny mroczny lord Sithów Imponujące bardzo imponujące. 1.7 Podsumowanie Silverlight jest jedną z najbardziej obiecujących platform programistycznych pochodzących z firmy Microsoft od pierwszego ukazania się.net dekadę temu. Silverlight wypełnia niszę pomiędzy tradycyjnymi aplikacjami pulpitowymi, a aplikacjami WWW oferując możliwości niedostępne w obu z nich. Dokonuje tego poprzez niewielką wtyczkę, której zainstalowanie zajmuje kilka minut i która działa na różnych przeglądarkach oraz w różnych systemach operacyjnych. Pisany kod i zdobywane umiejętności można wykorzystywać na komputerze osobistym, w sieci WWW, w urządzeniach przenośnych, na konsolach do gier w salonie oraz urządzeniach do odbioru telewizji. To całkiem niezły zwrot z inwestycji. Technologia Silverlight przeszła długą drogę od wersji Silverlight 2 omawianej w pierwotnym wydaniu książki. To zadziwiające, jak dużo zespoły produktowe były w stanie upakować w tym produkcie podczas tych dwóch lat. Zanim dołączyłem do firmy Microsoft, słyszałem pogłoski o ludziach śpiących w śpiworach w swoich biurach i kawie dostarczanej litrami.
22 Rozdział 1 Wprowadzenie do Silverlight Podejrzewam, że teraz wiem, dla którego zespołu pracują i muszę powiedzieć, że jestem pod dużym wrażeniem ich wyników. Przygotowaliśmy środowisko programistyczne i zaostrzyliśmy sobie apetyt budując prostą aplikację w Silverlight 4. W następnym rozdziale zagłębimy się w istotę działania interfejsu użytkownika Silverlight: język XAML. Od tego momentu kolejno przejrzymy wszystkie funkcje, które ta platforma ma do zaoferowania.
2 Fundamenty XAML Ten rozdział omawia Podstawy XAML, w tym sposób przedstawiania obiektów, właściwości, zdarzeń, poleceń i zachowań Struktury wykorzystywane przez Silverlight podczas pracy z XAML Wykorzystanie i tworzenie rozszerzeń XAML Tworzenie XAML podczas działania programu Wybór narzędzi do pracy z XAML Przed wynalezieniem WPF i Silverlight poszczególne języki i platformy programowania korzystały z różnych sposobów do określania interfejsu użytkownika. Większość z nich propaguje pojęcie oddzielania interfejsu użytkownika od kodu implementacyjnego. W niektórych przypadkach, takich jak HTML i CSS w sieci WWW, przedstawienie interfejsu użytkownika było teoretycznie oddzielone od jego wewnętrznej implementacji, ale nie było to całkiem prawdziwe, dopóki nie zaczęto stosować wypróbowanych wzorców, takich jak Model-View- -Controller (MVC). W innych przypadkach, takich jak Windows Forms, oddzielenie to powodowane było jedynie przez ukryte, automatycznie generowane i niemożliwe do edycji pliki, które zawierały specyficzny dla danego języka kod konieczny do utworzenia interfejsu użytkownika. Wraz z technologią WPF firma Microsoft wprowadziła język XAML, aby zapewnić wyraźniejszy rozdział obowiązków pomiędzy definiowaniem interfejsu użytkownika a kodem sterującym jego działaniem. Nie tylko pozwala to stosować sprytne wzorce projektowe, takie jak MVVM, czyli ViewModel (omówiony w rozdziale 16, a tutaj nazywany po prostu wzorcem ViewModel), ale też ułatwia tworzenie narzędzi.
24 Rozdział 2 Fundamenty XAML Rozważmy przez chwilę technologię Windows Forms. Definicja interfejsu była tak powiązana z kompilatorem i istniejącymi narzędziami, że niezwykle trudno było firmom trzecim tworzyć narzędzia projektujące interfejs użytkownika (lub wspomagające jego projektowanie). Pliki były ukryte, tworzone w wielu językach implementacyjnych i zawierały na początku wygenerowanego kodu komentarz ostrzegający przed próbami jego edytowania. W swoim czasie było to dobre, ale świat poszedł naprzód. Język XAML pomaga rozwiązać te problemy pozwala programistom, a nie narzędziom, decydować o interfejsie użytkownika. Pliki XAML można edytować i są one względnie odizolowane od reszty projektu. Pliki XAML można edytować przy pomocy Expression Blend, Visual Studio, Notatnika, Kaxaml i innych narzędzi wymienionych na końcu tego rozdziału, co ułatwia włączanie ich do własnego, specyficznego przepływu zadań przy pracy nad projektem. Nawet ręcznie edytowany kod XAML może być ponownie wykorzystywany przez narzędzia, ponieważ reguły XAML są dobrze zdefiniowane oraz spójne wewnętrznie i pomiędzy językami implementacyjnymi. Język XAML jest tak fundamentalny dla technologii Silverlight, że cały ten rozdział jest poświęcony wprowadzeniu do tego języka. Chociaż kod XAML pojawia się w niemal każdym rozdziale tej książki, to tutaj omówimy podstawowe pojęcia umożliwiając zapoznanie się z nimi na tyle, aby w przypadku otwarcia pliku XAML w Visual Studio lub Notatniku można było przeczytać i zrozumieć jego kod nawet na etapie uczenia się technologii Silverlight. Dla zainteresowanych wewnętrznym przetwarzaniem i zastosowaniem XAML podałem informacje dotyczące struktur drzewiastych, tworzenia własnych konwerterów i pracy z systemem właściwości. 2.1 Podstawy XAML XAML jest językiem deklaratywnym, który umożliwia nam tworzenie i inicjowanie obiektów.net w XML. Wszystko, co można zrobić w XAML, można też zrobić w kodzie. Aby jednak maksymalnie wykorzystać tę platformę i jej narzędzia, warto stosować filozofię kod plus znaczniki, zamiast decydować się na rozwiązania oparte w 100 procentach na kodzie. Format XAML umożliwia nam łatwą wizualizację hierarchii elementów oddzielając przy tym przedstawienie interfejsu od kodu. To oddzielenie jest możliwe, ponieważ każdemu elementowi XAML odpowiada typ.net. Każdy atrybut wewnątrz elementu odpowiada właściwości typu.net. Ta zasada jest zilustrowana na rysunku 2.1. Rysunek 2.1 pokazuje trzy odpowiedniki fragmentu XAML w kodzie. Warto zwrócić uwagę, że elementowi TextBlock w kodzie XAML odpowiada instrukcja inicjująca we fragmentach kodu. Inicjacja ta następuje, ponieważ za każdym razem, gdy jakiś element jest tworzony w XAML, w tle wywoływany jest domyślny konstruktor odpowiadającego mu typu.net. Aby zrozumieć strukturę pliku XAML, ważne jest zrozumienie przedstawienia i wykorzystania obiektów, przestrzeni nazw, właściwości i zdarzeń.
Podstawy XAML 25 IronRuby {tb = wpf.textblock() tb.text = "Hello, World" tb.fontfamily = "Verdana" XAML Visual Basic <TextBlock x:name="tb" Dim tb As New TextBlock Text="Hello, World" tb.text = "Hello, World" FontFamily="Verdana"/> tb.fontfamily = "Verdana" C# TextBlock tb = new TextBlock(); tb.text = "Hello, World"; tb.fontfamily = "Verdana"; Rysunek 2.1 Kod znacznikowy XAML reprezentuje obiekty.net. Wszystko, co można zrobić w XAML, można zrobić w kodzie. 2.1.1 Obiekty Obiekty (albo wystąpienia typów) są przedstawiane w XAML przy użyciu elementów XML. Elementy te mają taką samą nazwę, jak powiązana klasa i są uważane za zainicjowane w momencie zadeklarowania przez dany znacznik. UWAGA Każdy typ używany w XAML musi mieć konstruktora domyślnego (bez parametrów). XAML w Silverlight obecnie nie pozwala przekazywać argumentów do konstruktora lub funkcji inicjującej, więc trzeba zapewnić, aby typy mogły być inicjowane wyłącznie przy pomocy wartości domyślnych i właściwości. Pewne typy obiektów mogą zawierać jeden lub więcej innych zagnieżdżonych obiektów. Na przykład przycisk może zawierać pojedynczy obiekt zawartości, który z kolei może zawierać jeden lub więcej innych obiektów. Na wydruku 2.1, element UserControl zawiera element Grid, element Grid zawiera element Button, a Button zawiera element StackPanel, który jest pojemnikiem domyślnie układającym swoje elementy podrzędne w formie pionowej listy. Sam element StackPanel zawiera trzy elementy TextBlock.
26 Rozdział 2 Fundamenty XAML Wydruk 2.1 Kod XAML pokazujący hierarchię zagnieżdżonych obiektów Wynik: XAML: <UserControl x:class="xamlelements.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid x:name="layoutroot"> <Button Height="100" Width="150"> <StackPanel> <TextBlock Text="Pierwszy wiersz" /> <TextBlock Text="Drugi wiersz" /> <TextBlock Text="Trzeci wiersz" /> </StackPanel> </Button> </Grid> </UserControl> Najbardziej zewnętrzny element UserControl Zagnieżdżony element Grid Element Button zagnieżdżony w elemencie Grid Trzy elementy TextBlock w elemencie StackPanel StackPanel wewnątrz elementu Button Elementy UserControl i Button są kontrolkami z zawartością, które to pojęcie omówimy dokładniej w rozdziale 10. Na razie ważne jest, aby zrozumieć, że kontrolka z zawartością może mieć tylko jeden bezpośrednio podrzędny elementy zazwyczaj jest to panel zawierający inne elementy. Właściwości x:name i x:class są częścią przestrzeni nazw określonej przez instrukcję xmlns:x. Więcej na ten temat za chwilę Elementy Grid i StackPanel wywodzą się z elementu Panel, który jest typem zawierającym kolekcję Children, co pozwala mu zawierać wiele elementów podrzędnych. Panele omówimy w rozdziale 7. Możliwość elastycznego zagnieżdżania obiektów pozwala na stosowanie kompozycyjnego podejścia do projektowania interfejsu użytkownika. Zamiast konieczności kupowania lub specjalnego kodowania kontrolki przycisku pozwalającej powiedzmy na trzy wiersze tekstu i rysunek, możemy po prostu złożyć te elementy w odpowiednim panelu i uczynić ten panel zawartością kontrolki przycisku. Zagnieżdżanie obiektów umożliwia nam drzewo obiektów. Wkrótce omówimy to dokładniej. Teraz, gdy zapoznaliśmy się z podstawową strukturą pliku XAML, zajmijmy się przestrzeniami nazw, które pozwalają nam odróżnić czyjąś kontrolkę SuperButton od naszej własnej kontrolki SuperButton, nawet jeśli użyliśmy tej samej nazwy kontrolki.
Podstawy XAML 27 2.1.2 Przestrzenie nazw Przestrzeń nazw zapewnia sposób organizowania powiązanych obiektów we wspólną grupę. Te grupy, czyli przestrzenie nazw stanowią sposób definiowania, gdzie kompilator powinien szukać danego typu. Przestrzenie nazw w XAML są podobne do przestrzeni nazw w innych językach, takich jak C# i Java. Aby określić, gdzie trzeba szukać, odwołujemy się do przestrzeni nazw wewnątrz elementu pliku XAML, zwykle w elemencie głównym, czyli najbardziej zewnętrznym. Wydruk 2.2 ilustruje zastosowanie dwóch domyślnych przestrzeni nazw. Wydruk 2.2 Podstawowy plik XAML odwołujący się do dwóch domyślnych przestrzeni nazw <UserControl x:class="xaml01.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot" Background="White"> <TextBlock x:name="mytextblock" Text="Hello" /> </Grid> </UserControl> UWAGA WPF obsługuje właściwość Name w obu przestrzeniach nazw zarówno poprzedzonej przedrostkiem x:, jak i w domyślnej przestrzeni nazw, co pozwala określać je jako x:name lub po prostu Name. Silverlight obsługuje tylko x:name. Dla zachowania zgodności ze znacznikami Silverlight, zalecanym podejściem dla WPF jest stosowanie x:name. Jak ilustruje wydruk 2.2, można odwoływać się do wielu przestrzeni nazw w pojedynczym pliku XAML. Gdy odwołujemy się do wielu przestrzeni nazw, każda przestrzeń nazw musi być poprzedzona unikalnym przedrostkiem. Na przykład przedrostek x w tym przykładzie jest używany w powiązaniu z przestrzenią nazw http://schemas.microsoft.com/winfx/2006/xaml. Jednocześnie przestrzeń nazw http://schemas.microsoft.com/winfx/2006/xaml/presentation nie używa przedrostka. Standardowe przestrzenie nazw XAML Te dwie właśnie wymienione przestrzenie nazw będą używane w niemal każdej aplikacji Silverlight, z którą nam przyjdzie pracować. Te przestrzenie nazw są zwykle definiowane w następujący sposób: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" to jest domyślna przestrzeń nazw Silverlight. Zapewnia naszym aplikacjom podstawowe elementy Silverlight. Z tego powodu ta przestrzeń nazw zwykle pomija przedrostek, co czyni z niej domyślną przestrzeń nazw na stronie. Takie podejście umożliwia nam odwoływanie się do elementów w tej określonej przestrzeni nazw bez konieczności dołączania przedrostka.
28 Rozdział 2 Fundamenty XAML xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" to jest wspólna przestrzeń nazw dla XAML. Zapewnia funkcjonalność wspólną dla różnych odmian języka XAML. Ważne jest, aby pamiętać, że język XAML jest używany też w innych technologiach, takich jak WPF, Oslo i Windows Workflow Foundation (WF), z których wszystkie muszą mieć dostęp do wspólnych funkcji, takich jak właściwości Name, Key i Class. UWAGA Oprócz standardowych przestrzeni nazw, środowisko uruchomieniowe Silverlight obsługuje też specyficzną dla Silverlight przestrzeń nazw http://schemas.microsoft.com/ client/2007 jako domyślną przestrzeń nazw. Należy jednak korzystać z wcześniej wymienionej przestrzeni nazw http://schemas.microsoft.com/winfx/2006/xaml/presentation jako domyślnej, ponieważ Expression Blend, Visual Studio i inne narzędzia są wszystkie skonfigurowane na rozpoznawanie tej przestrzeni nazw. Użycie standardowych przestrzeni nazw również ułatwia wymianę kodu znacznikowego z aplikacjami WPF. Odwoływanie się do innych bibliotek Gdy odwołujemy się do innego podzespołu, jest on kopiowany do zależnego od konfiguracji foldera Bin w naszej aplikacji Silverlight. W istocie, gdy kompilujemy aplikację Silverlight, to jest ona kompilowana do podzespołu, który jest umieszczany w tym katalogu. Model aplikacji omówimy później; na razie, aby odwoływać się do tych podzespołów, musimy zdefiniować nową przestrzeń nazw XAML, która zawiera przedrostek, przestrzeń nazw CLR i nazwę podzespołu. Wydruk 2.3 ilustruje to zagadnienie. Wydruk 2.3 Wykorzystanie kontrolki z zewnętrznego podzespołu <UserControl x:class="xaml02.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:my="clr-namespace:mynamespace;assembly=myassembly" Width="400" Height="300"> <Grid x:name="layoutroot"> <my:mycontrol x:name="mycontrol1" /> Użycie podzespołu </Grid> </UserControl> Odwołanie do zewnętrznego podzespołu Jak ilustruje wydruk 2.3, odwoływanie się do innych elementów, w tym elementów niestandardowych, wymaga od nas jedynie podania przestrzeni nazw i nazwy podzespołu zawierającego element zewnętrzny. Oczywiście nadal trzeba dodać odwołanie do zewnętrznego podzespołu, aby jego typy były dostępne w kodzie i dla parsera/kompilatora XAML. Dla wygody została tutaj użyta nazwa my; można użyć dowolnego, sensownego identyfikatora. Jeśli typ, do którego się odwołujemy, jest zdefiniowany w tym samym podzespole, co kod znacznikowy, to nadal musimy utworzyć dla niego odwołanie do przestrzeni nazw XAML. Natomiast fragment ;assembly= w definicji przestrzeni nazw może zostać opcjonalnie pominięty, jak to pokazano na wydruku 2.4.
Podstawy XAML 29 Wydruk 2.4 Korzystanie z kontrolki z innej przestrzeni nazw w tym samym podzespole <UserControl x:class="xaml03.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:xaml03.controls" Width="400" Height="300"> <Grid x:name="layoutroot"> <controls:mycontrol x:name="mycontrol1" /> </Grid> </UserControl> Odwołanie do przestrzeni nazw Użycie przestrzeni nazw Przestrzenie nazw są zwykle deklarowane w najbardziej zewnętrznym elemencie pliku XAML, jak na wydruku 2.4, ale nie musi to być regułą. W przypadku korzystania z kodu XAML generowanego przez narzędzia, czasami natrafimy na przestrzenie nazw definiowane na niższych poziomach, zwłaszcza wewnątrz szablonów kontrolek (co omówiono w rozdziale 23). W tych przypadkach przestrzeń nazw odnosi się tylko do elementów wewnątrz danego typu (oraz do samego elementu obejmującego te wewnętrzne elementy), a nie do całego dokumentu XAML. Wydruk 2.5 pokazuje definicję przestrzeni nazw na poziomie Grid zamiast na poziomie UserControl. Przestrzeń nazw mogłaby też być zdefiniowana na poziomie MyControl, ale wtedy musielibyśmy robić to dla każdego wystąpienia MyControl. To podejście jest czasami stosowane podczas korzystania z szablonów kontrolek i w innych sytuacjach, gdy chcemy zminimalizować możliwe kolizje przedrostków przestrzeni nazw, zachowując przy tym możliwość odwoływania się do kodu zewnętrznego. Wydruk 2.5 Deklaracja przestrzeni nazw na poziomie niższym niż element główny <UserControl x:class="xaml04.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot" xmlns:controls="clr-namespace:xaml03.controls"> <controls:mycontrol x:name="mycontrol1" /> <controls:mycontrol x:name="mycontrol2" /> <controls:mycontrol x:name="mycontrol3" /> </Grid> </UserControl> Deklaracja przestrzeni nazw Przestrzeń nazw pokazana na wydruku 2.5 będzie stosowana tylko wobec siatki LayoutRoot i jej elementów potomnych. Kontrolki poza tą hierarchią nie będą miały dostępu do przestrzeni nazw controls lub jej przedrostka. Zwykle spotkamy się z tym wewnątrz skomplikowanych stylów w słownikach zasobów. Te same podejścia do odwoływania się do przestrzeni nazw i podzespołów mają zastosowanie w przypadku słowników zasobów, stron i innych typów powszechnie związanych z XAML. Choć zrozumienie reguł odwoływania się do przestrzeni nazw jest ważne, to w praktyce narzędzia będą za nas same tworzyć przestrzenie nazw dzięki IntelliSense lub podczas przeciągania i upuszczania elementów w edytorze lub na obszarze projektowym.
30 Rozdział 2 Fundamenty XAML 2.1.3 Właściwości Istnieją dwa sposoby odwoływania się do właściwości w XAML: wewnątrz elementu tak, jak w przypadku dowolnego atrybutu XML, i poprzez zagnieżdżony podelement. Z którego sposobu należy skorzystać, zależy od tego, co mamy przedstawić. Proste wartości są zwykle reprezentowane przez właściwości wewnętrzne, natomiast skomplikowane wartości są zwykle reprezentowane przez osobne elementy. Właściwości wewnętrzne Zastosowanie wewnętrznej właściwości wymaga konwertera typu, który będzie konwertował zapis tekstowy na przykład "Black" w wyrażeniu Background="Black" na właściwy typ.net (w tym przypadku SolidColorBrush). Konwertery typów omówimy później w tym rozdziale. Przykład na wydruku 2.6 pokazuje wbudowany konwerter typu w działaniu podczas konwersji łańcucha tekstowego "Black" dla wewnętrznej właściwości Background. Wydruk 2.6 Określanie wartości właściwości wewnątrz elementu przy użyciu atrybutu XML <UserControl x:class="xaml05.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot" Background="Black" /> </UserControl> Właściwość wewnętrzna Właściwości w osobnych elementach Innym sposobem określania właściwości jest zastosowanie rozszerzonej składni elementów określających właściwości. Choć może to być w ogólności stosowane dla dowolnej właściwości, to jest to zwykle wymagane tylko wtedy, gdy musimy określić coś bardziej skomplikowanego, na co nie pozwala w prosty sposób składnia wewnątrz elementu. Składnią dla właściwości w osobnych elementach jest <Typ.NazwaWłaściwości>wartość</Typ.Nazwa- Właściwości>, jak pokazano na wydruku 2.7. Wydruk 2.7 Określanie wartości właściwości przy użyciu składni z osobnym elementem <UserControl x:class="xaml06.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot"> <Grid.Background> Black </Grid.Background> </Grid> </UserControl> Składnia właściwości w osobnym elemencie Użycie łańcucha tekstowego w celu wywołania konwertera typu jest w efekcie tożsame z zastosowaniem <SolidColorBrush Color="Black" /> w miejsce "Black". Chociaż te przykłady są rzadko
Podstawy XAML 31 spotykane w praktyce, to powszechny jest bardziej skomplikowany przykład ustawiania tła jako LinearGradientBrush, więc omówimy to w następnej kolejności. Zamiast reprezentować wartość jako prosty łańcuch tekstowy taki, jak "Black", wartość ta może być elementem zawierającym złożony zestaw elementów i właściwości takim, jak <LinearGradientBrush> pokazany na wydruku 2.8. Wydruk 2.8 Bardziej skomplikowany przykład składni elementu reprezentującego właściwość <UserControl x:class="xaml07.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot"> <Grid.Background> <LinearGradientBrush> Właściwość Background <LinearGradientBrush.GradientStops> <GradientStop Offset="0.0" Color="Black" /> <GradientStop Offset="0.5" Color="LightGray" /> <GradientStop Offset="0.5" Color="DarkGray" /> <GradientStop Offset="1.0" Color="White" /> </LinearGradientBrush.GradientStops> </LinearGradientBrush> </Grid.Background> </Grid> </UserControl> Typ pędzla Więcej elementów właściwości Gdy już wiemy, jak określać właściwości w kodzie znacznikowym, zagłębmy się bardziej w sposób działania tych właściwości. 2.1.4 Właściwości zależnościowe Właściwości zależnościowe są częścią systemu właściwości wprowadzonym w WPF i wykorzystywanym też w Silverlight. W znacznikach i w kodzie są one nie do odróżnienia od standardowych właściwości środowiska uruchomieniowego.net, z tym że mogą być wiązane z danymi, służyć jako cele animacji lub być ustawiane przez style. WSKAZÓWKA Właściwość nie może być celem animacji, ani uzyskiwać swojej wartości poprzez wiązanie, o ile nie jest właściwością zależnościową. Wiązanie omówimy dokładnie w rozdziale 11. Aby klasa mogła mieć właściwości zależnościowe, musi wywodzić się z klasy DependencyObject lub jednej z jej podklas. Zwykle robi się to tylko dla elementów wizualnych i innych elementów, które będziemy wykorzystywać wewnątrz XAML, a nie w klasach definiowanych poza interfejsem użytkownika. W zwykłym kodzie.net, gdy tworzymy właściwość, to zwykle wspieramy ją przez prywatne pole w danej klasie. Przechowywanie właściwości zależnościowej różni się tym, że lokalizacja wspierającej ją wartości zależy od jej aktualnego stanu. Sposób ustalania tej lokalizacji jest zwany pierwszeństwem wartości.
32 Rozdział 2 Fundamenty XAML Pierwszeństwo wartości Właściwości zależnościowe uzyskują swoją wartość z różnych danych wejściowych. Poniżej przedstawiono kolejność, którą system właściwości w Silverlight wykorzystuje podczas przypisywania wartości właściwościom zależnościowym w trakcie działania aplikacji, przy czym najpierw jest wymieniony najwyższy priorytet: Aktywne lub wstrzymane animacje Animacje będą wpływać na wartość bazową właściwości zależnościowej w zależności od ustalenia pierwszeństwa dla innych danych wejściowych. Aby animacja miała jakiś wpływ, musi mieć najwyższy priorytet. Animacje mogą działać na pojedynczą właściwość zależnościową z wielu poziomów pierwszeństwa (na przykład, animacja zdefiniowana w szablonie kontrolki i animacja zdefiniowana lokalnie). Wartość zwykle wynika ze złożenia wszystkich animacji, w zależności od animowanego typu. Wartość lokalna Wartości lokalne są określane bezpośrednio w kodzie znacznikowym i są dostępne poprzez opakowania właściwości CLR dla właściwości zależnościowej. Ponieważ wartości lokalne mają pierwszeństwo przed stylami i szablonami, to mogą przedefiniowywać wartości, takie jak styl czcionki lub kolor pierwszoplanowy, zdefiniowane w domyślnym stylu dla danej kontrolki. Właściwości szablonowe Używane w szczególności wobec elementów tworzonych wewnątrz kontrolki lub szablonu danych, a ich wartość jest pobierana z samego szablonu. Ustawienia stylów Są to wartości ustawiane w aplikacji dla stylu poprzez zasoby definiowane lub scalane w słownikach zasobów dla elementu UserControl lub aplikacji. Style zbadamy w rozdziale 23. Wartość domyślna Jest to wartość zapewniana lub przypisywana podczas pierwszego utworzenia właściwości zależnościowej. Jeśli nie podano wartości domyślnej, to mają zastosowanie typowe wartości domyślne dla typów CLR. Ścisłe reguły pierwszeństwa pozwalają nam polegać na określonych zachowaniach w Silverlight, na przykład możliwości przedefiniowywania elementów stylu poprzez ustawianie ich jako wartości lokalnych w samym elemencie. Na wydruku 2.9 kolorem pierwszoplanowym przycisku będzie czerwony, jak to zostało ustawione w wartości lokalnej, a nie czarny, jak to zostało ustawione w stylu. Wartość lokalna ma wyższy priorytet niż zastosowany styl. Wydruk 2.9 Reguły pierwszeństwa właściwości zależnościowej w praktyce <UserControl x:class="xaml08.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <UserControl.Resources> <Style x:key="buttonstyle" TargetType="Button"> <Setter Property="Foreground" Value="Black" /> <Setter Property="FontSize" Value="24" />
Podstawy XAML 33 </Style> </UserControl.Resources> <Grid x:name="layoutroot"> <Button Content="Local Values at Work" Style="{StaticResource ButtonStyle}" Foreground="Red" /> </Grid> </UserControl> Znacznik Style w UserControl.Resources określa zasób wielokrotnego użytku, który ustawia pewne kluczowe właściwości dla naszego przycisku. Omówimy tworzenie właściwości zależnościowych w rozdziale 24, kiedy będziemy tworzyć swoje własne kontrolki. Dla celów tego rozdziału wystarczy zrozumieć, że większość właściwości, do których odwołujemy się w XAML, jest właściwościami zależnościowymi. Jednym z typów właściwości zależnościowych, który ma nieco dziwny wygląd, jest właściwość połączona. 2.1.5 Właściwości połączone Właściwości połączone są wyspecjalizowanym typem właściwości zależnościowych, który można natychmiast rozpoznać w kodzie znacznikowym ze względu na składnię Nazwa- Typu.NazwaWłaściwościPołączonej. Na przykład Canvas.Left jest właściwością połączoną definiowaną przez typ Canvas. To co sprawia, że właściwości połączone są interesujące, jest to, że nie są one definiowane przez typ, w którym są używane, ale są definiowane przez inny typ w potencjalnie innej hierarchii klas. Właściwości połączone pozwalają na elastyczność przy definiowaniu klas, ponieważ klasy nie muszą brać pod uwagę wszystkich możliwych scenariuszy, w których będą używane i definiować właściwości dla wszystkich tych scenariuszy. Układ elementów jest tego świetnym przykładem. Elastyczność systemu układu w Silverlight pozwala nam tworzyć nowe panele, które mogłyby nigdy nie zostać zaimplementowane w innych technologiach na przykład panel układający elementy pod różnymi kątami i na różnych poziomach w układzie kołowym bądź radialnym, zamiast czegoś na kształt wbudowanego elementu Canvas, który układa elementy według ich właściwości Left i Top. Zamiast definiować we wszystkich elementach właściwości Left, Top, Level i Degrees (a także właściwości GridRow i GridColumn dla siatek), możemy zastosować właściwości połączone. Na przykład przyciski na wydruku 2.10 są zawarte w panelach, które mają znacznie różniące się algorytmy układu, wymagające różnych informacji o pozycjach elementów. W tym przypadku pokażemy fikcyjny element RadialPanel w użyciu. Wydruk 2.10 Właściwości połączone w użyciu <UserControl x:class="xaml09.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:panels="clr-namespace:xaml09.panels"
34 Rozdział 2 Fundamenty XAML Width="400" Height="600"> <StackPanel x:name="layoutroot"> <Canvas Width="400" Height="200"> <Button Canvas.Left="10" #A Canvas.Top="50" #A Width="200" Height="100" Content="Button in Canvas" /> </Canvas> Właściwości połączone <panels:radialpanel Width="400" Height="400"> <Button panels:radialpanel.degrees="25" panels:radialpanel.level="3" Width="200" Height="100" Content="Button in Radial Panel" /> </panels:radialpanel> </StackPanel> </UserControl> Właściwości połączone nie ograniczają się do układu elementów. Spotkamy je w silniku animacji dla właściwości, takich jak Storyboard.TargetProperty, a także w innych miejscach platformy. Ścieżki właściwości Zanim podsumujemy naszą dyskusję na temat właściwości, pozostało nam jeszcze jedno pojęcie do zrozumienia: ścieżki właściwości. Ścieżki właściwości zapewniają sposób odwoływania się do właściwości obiektów w XAML zarówno wtedy, gdy mamy nazwę elementu, jak i gdy musimy pośrednio odwoływać się do elementu poprzez jego pozycję w drzewie elementów. Ścieżki właściwości mogą przyjmować kilka postaci i mogą prowadzić do właściwości obiektu. Mogą też wykorzystywać nawiasy do pośredniego określania celów właściwości oraz do określania właściwości połączonych. Oto kilka przykładów ścieżek właściwości dla właściwości określających cel elementu Storyboard: <DoubleAnimation Storyboard.TargetName="MyButton" Storyboard.TargetProperty="(Canvas.Left)"... /> <DoubleAnimation Storyboard.TargetName="MyButton" Storyboard.TargetProperty="Width"... />... <Button x:name="mybutton" Canvas.Top="50" Canvas.Left="100" /> Ścieżki właściwości omówimy szczegółowo w rozdziale 11, gdy będziemy omawiać wiązania. Właściwości należą do elementów, które definiują interfejs obiektu. Ponieważ XAML nie pozwala nam nic robić przy pomocy metod, jedyną pozostałą częścią interfejsu jest definicja zdarzeń.
Podstawy XAML 35 2.1.6 Zdarzenia Zdarzenia w Silverlight są używane podobnie do zdarzeń w dowolnej innej technologii.net. Nadawca zdarzenia chce powiadomić nieokreśloną liczbę odbiorców o czymś, co się wydarzyło. Silverlight rozszerza to jednak w ten sposób, że zdarzenia mogą wędrować w górę drzewa obiektów od źródła zdarzenia do elementu głównego. Silverlight i WPF wprowadzają pojęcia zdarzeń wytyczanych i wypływania zdarzeń na powierzchnię. Pozwala to na generowanie zdarzeń na jednym poziomie drzewa, a następnie zapewnia możliwość obsłużenia ich przez każdy wyższy poziom, aż do osiągnięcia elementu głównego drzewa efekt ten jest znany jako wypływanie na powierzchnię. Dla procedury obsługującej zdarzenia główną różnicę pomiędzy zdarzeniami wytyczanymi a standardowymi zdarzeniami CLR stanowi to, że nadawca zdarzenia nie jest koniecznie pierwotnym źródłem tego zdarzenia. Aby uzyskać pierwotne źródło zdarzenia, trzeba sprawdzić właściwość OriginalSource w argumencie RoutedEventArgs przekazanym do procedury obsługi zdarzenia. Zdarzenia tworzone przez użytkowników, jak te, które możemy tworzyć w swoim własnym kodzie, nie mogą wypływać na powierzchnię. Wypływanie na powierzchnię jest zarezerwowane tylko dla wbudowanych zdarzeń podstawowych, takich jak MouseLeftButtonDown. Zdarzenia wypływające na powierzchnię zawierają właściwość Handled wśród argumentów zdarzenia obok standardowych informacji RoutedEventArgs. Zdarzenia wytyczane w WPF Kto zna system zdarzeń w WPF, może zastanawiać się, co stało się z typami zdarzeń wytyczanych Tunneling i Direct. Silverlight obecnie ich nie implementuje. W istocie Silverlight nie zawiera obiektu EventManager dostępnego w WPF, więc zdarzenia wytyczane nie mogą być tworzone w kodzie użytkownika. Niektórzy sprytni projektanci pracujący dla sprzedawców kontrolek zaimplementowali swoje własne odpowiedniki, które pozwalają na zdarzenia wytyczane tworzone przez użytkowników, ale nie jest to wbudowane w podstawowe środowisko uruchomieniowe Silverlight. Odwołania do zdarzeń w XAML W XAML odwoływanie się do procedur obsługi zdarzeń zdefiniowanych w kodzie jest proste. Jeśli korzystamy z Visual Studio, to procedura obsługi zdarzenia w kodzie może być tworzona automatycznie. Na przykład, jeśli mamy przycisk w XAML: <Button Click="MyButton_Click" /> Możemy połączyć go z odpowiednią procedurą obsługi zdarzenia w kodzie:
36 Rozdział 2 Fundamenty XAML private void MyButton_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Click event"); } To podejście jest dobrym skrótem do podłączania zdarzeń. Podczas pracy w XAML narzędzia Visual Studio pozwolą nam nawet zdefiniować nową procedurę obsługi zdarzenia lub użyć istniejącej. Pewną niewielką zaletą tego podejścia jest to, że niekoniecznie trzeba definiować nazwę dla danego przycisku. Odwołania do zdarzeń w kodzie Aby przyłączyć procedurę obsługi zdarzenia z poziomu kodu, stosujemy to samo podejście co przy każdym normalnym zdarzeniu CLR: tworzymy nową procedurę obsługi zdarzenia i dodajemy ją do zdarzenia korzystając ze składni +=. Jeśli więc mamy ten sam przycisk co wcześniej i nadamy mu nazwę, do której będziemy mogli się odwoływać w kodzie: <Button x:name="mybutton" /> to możemy wtedy przyłączyć procedurę obsługi zdarzenia w konstruktorze. Należy to zrobić po wywołaniu InitializeComponent, aby nazwa MyButton była prawidłowa: public MainPage() { InitializeComponent(); MyButton.Click += new RoutedEventHandler(MyButton_Click); } private void MyButton_Click(object sender, RoutedEventArgs e) { MessageBox.Show("Click event"); } Oba podejścia są równie poprawne. Zastosowane podejście będzie przede wszystkim zależeć od osobistego stylu. Moim ulubionym podejściem, gdy nie korzystam z poleceń, jest przyłączanie zdarzeń w kodzie konstruktora, jak pokazano to tutaj. Wersja Silverlight 4 dodała możliwość użycia poleceń jako sposobu na oczyszczenie kodu obsługi zdarzeń i ich przyłączania. Zamiast określać procedurę obsługi zdarzenia, możemy określić jedną lub kilka właściwości poleceń w XAML. 2.1.7 Polecenia Jednym z najważniejszych architektonicznie dodatków do Silverlight 4 było dodanie poleceń w stylu WPF. Polecenia pozwalają nam usuwać pośredniczące procedury obsługi zdarzenia z kodu, gdy chcemy, aby coś innego niż kod obsłużyło dane działanie. Na przykład, jeśli stosujemy wzorzec ViewModel, to prawdopodobnie chcemy, aby kliknięcia przycisków były obsługiwane przez model widoku (view model), a nie kod. Typowy kod procedury obsługi zdarzenia przekazujący dane zdarzenie mógłby wyglądać następująco:
Podstawy XAML 37 private void Save_Click(object sender, RoutedEventArgs e) { _viewmodel.save(); } Jest to dodatkowy element, który niekoniecznie jest pożądany w naszym widoku. Komplikuje to testy jednostkowe i sprawia, że kod strony staje się niezbędnym składnikiem. Wymaga to też rozdzielenia właściwości modelu widoku w celu ustawienia właściwości IsEnabled dla przycisku Save. Nie ma tragedii, ale mogłoby być lepiej. Kod polecenia, który eliminuje ten kod strony, mógłby wyglądać następująco: // nie potrzeba żadnego kodu strony :) Kocham kod, którego nie muszę pisać. Wszystko jest obsługiwane w znacznikach i modelu widoku, więc nie musimy w ogóle przekazywać kodu dalej. Kontrolki w widoku są powiązane z poleceniami, które istnieją gdzieś na ścieżce wiązania. Zakładając, że mamy ustawiony kontekst danych dla strony na model widoku, kod znacznikowy wiązany z udostępnianym poleceniem modelu widoku wygląda następująco: <Button x:name="savebutton" Height="25" Width="75" Content="Save" Command="{Binding SaveCommand}" /> Powiązane elementy modelu widoku mogłyby wyglądać jak poniżej zakładając, że zaimplementowaliśmy polecenie EmployeeSaveCommand, które implementuje interfejs ICommand: private EmployeeSaveCommand _savecommand; public ICommand SaveCommand { get { return _savecommand; } } W ten sposób unikamy sytuacji, gdy kod strony stoi na przeszkodzie oddzieleniu widoku od modelu widoku. Polecenia również zapewniają inne możliwości, takie jak automatyczne wyłączanie powiązanych kontrolek, jeśli polecenie nie może być uruchomione w tym czasie poprzez domniemane powiązanie metody ICommand.CanExecute z właściwością IsEnabled przycisku. Polecenia są obsługiwane przez wszelkie kontrolki, które dziedziczą po ButtonBase, jak również przez kontrolkę Hyperlink (nie mylić z kontrolką HyperlinkButton, która dziedziczy po ButtonBase). Utworzymy swoje własne polecenia w rozdziale 16, gdy będziemy omawiać, jak budować aplikacje korzystając ze wzorca ViewModel. Innym interesującym elementem dołączonej funkcjonalności, z którą możemy się spotkać w kodzie znacznikowym, są zachowania.
38 Rozdział 2 Fundamenty XAML 2.1.8 Zachowania Zachowania są elementami interaktywnymi opakowanymi w sposób przyjazny dla projektantów, wprowadzonymi w wersji Silverlight 3, pierwotnie powiązanymi z Expression Blend w celu ułatwienia możliwości przeciągania ich bezpośrednio na powierzchnię projektową i kojarzenia ich z kontrolkami. Zachowania obejmują takie możliwości, jak prawa fizyki, dźwięk, automatyczne cienie, przeciąganie i upuszczanie, a nawet zachowania niewizualne, takie jak to, które jest używane do powiązania zdarzeń zamykania okna z modelem widoku w WPF. Było to atrakcyjne nie tylko dla użytkowników Blend, więc funkcjonalność ta została udostępniona wszystkim programistom Silverlight i WPF. Pakiet SDK zawiera wiele domyślnych zachowań, jak również mnóstwo zachowań utworzonych przez członków społeczności dla Silverlight i WPF na witrynie społecznościowej pakietu Expression. Rysunek 2.2 pokazuje sekcję Behaviors panelu Assets w programie Expression Blend wymieniającą osiem dołączonych zachowań. Rysunek 2.2 Domyślne zachowania w Expression Blend zawierają elementy związane z całą gamą interakcji, od praktycznych do skomplikowanych, takich jak przeciąganie i upuszczanie. Dodatkowe zachowania można znaleźć w witrynie Microsoft Expression Community Gallery pod adresem http://gallery. expression.microsoft.com. Zachowania zwykle nie wymagają użycia żadnego kodu, ponieważ są przyłączane przy użyciu XAML. Na przykład wydruk 2.11 pokazuje kod znacznikowy wymagany do użycia zachowania MouseDragElementBehavior, jednego z zachowań dostarczanych dla elementu Border. Wydruk 2.11 Zachowanie MouseDragElementBehavior przyłączone do elementu Border <UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="clr-namespace:system.windows.interactivity; assembly=system.windows.interactivity" xmlns:il="clr-namespace:microsoft.expression.interactivity.layout; assembly=microsoft.expression.interactions" x:class="silverlightapplicationbehavior.mainpage" Width="640" Height="480"> <Grid x:name="layoutroot" Background="White"> <Border Width="100" Height="100" Przestrzenie nazw wymagane przez zachowania
Drzewa obiektów i zakres nazw 39 BorderBrush="Black" Background="Orange" BorderThickness="2"> <i:interaction.behaviors> <il:mousedragelementbehavior/> </i:interaction.behaviors> Przyłączone zachowanie <TextBlock Text="Drag Me" HorizontalAlignment="Center" VerticalAlignment="Center" /> </Border> </Grid> </UserControl> Cały kod wymagany do zaimplementowania przeciągania obramowania jest zawarty wewnątrz tego zachowania. Zachowania są świetnym sposobem opakowywania typowej funkcjonalności interfejsu użytkownika, która mogłaby być stosowana wobec innych elementów interfejsu. Zachowania omówimy bardziej szczegółowo w rozdziale 22, gdzie również utworzymy swoje własne, niestandardowe zachowanie. Obiekty, właściwości, zdarzenia, polecenia i zachowania składają się na większość tego, co zobaczymy przeglądając plik XAML. W tym momencie powinniśmy być w stanie czytać pliki XAML i ogólnie rozumieć poszczególne elementy. Inną rzeczą, którą można zobaczyć w XAML, są nazwy obiektów i właściwości wewnątrz nawiasów klamrowych. Omówimy to później w tym rozdziale, ale najpierw przyjrzymy się, co widzi silnik Silverlight przeglądając źródło XAML i budując reprezentację poszczególnych elementów w pamięci. 2.2 Drzewa obiektów i zakres nazw W poprzednich częściach tego rozdziału wspominałem o pojęciu drzewa obiektów. Aby zrozumieć drzewo obiektów, musimy zrozumieć układ elementów i zawartość plików XAML. Wtedy będzie łatwiej wyobrazić sobie pojęcie drzewa obiektów i związane z nim pojęcie zakresu nazw. Częstym, błędnym wyobrażeniem jest to, że Silverlight tworzy XAML dla wszelkich obiektów tworzonych przez nas w kodzie. W istocie dzieje się odwrotnie: Silverlight tworzy obiekty na podstawie XAML. Obiekty tworzone przez nas w kodzie trafiają od razu do drzew obiektów w swojej wrodzonej formie obiektów.net. Elementy w XAML są przetwarzane i zamieniane na obiekty, które trafiają do tego samego drzewa. 2.2.1 Drzewa obiektów Gdy już omówiliśmy strukturę pliku XAML, możemy się jakiemuś przyjrzeć i szybko zdać sobie sprawę, że reprezentuje on hierarchiczne drzewo obiektów zaczynające się od elementu głównego (zwykle UserControl lub Page) i budowane kolejno przez różne kształty, panele i inne elementy, które składają się na wykorzystywane szablony kontrolek. Ta hierarchiczna struktura jest zwana drzewem obiektów. Rysunek 2.3 pokazuje hipotetyczne drzewo obiektów.
40 Rozdział 2 Fundamenty XAML UserControl Grid (LayoutRoot) ElementCollection (Children) TextBlock ListBox TextBlock ItemCollection (Items) TextBlock TextBlock TextBlock Rysunek 2.3 Hipotetyczne drzewo obiektów pokazujące nie tylko elementy wizualne, takie jak pola TextBlock i ListBox, ale też wewnętrzne kolekcje używane do przechowywania elementów podrzędnych. Każdy element ma swój element nadrzędny (w którym jest zawarty) i może mieć element lub elementy podrzędne we właściwościach będących kolekcjami, właściwościach określających zawartość lub innych właściwościach ogólnego przeznaczenia. UWAGA W odróżnieniu od WPF, Silverlight nie określa pojęcia drzewa logicznego. Operacje, które w WPF mogłyby zwracać informacje o drzewie logicznym, w Silverlight będą zwracać informacje o drzewie wizualnym. Ta różnica jest tak naprawdę ważna tylko dla tych, którzy przychodzą ze świata WPF lub przenoszą z WPF kod wykorzystujący funkcje przechodzące przez elementy drzewa. Drzewo wizualne jest przefiltrowanym widokiem drzewa obiektów. Podczas gdy drzewo obiektów zawiera wszystkie typy niezależnie od tego, czy biorą one udział w obrazowaniu (na przykład kolekcje), to drzewo wizualne zawiera tylko te obiekty, które mogą być przedstawione wizualnie. Rysunek 2.4 pokazuje drzewo wizualne; warto zwrócić uwagę na brak obiektów niewizualnych, takich jak kolekcje.
Drzewa obiektów i zakres nazw 41 UserControl Grid (LayoutRoot) TextBlock ListBox TextBlock TextBlock TextBlock TextBlock Rysunek 2.4 Przedstawienie drzewa obiektów z rysunku 2.3 w postaci drzewa wizualnego. Warto zwrócić uwagę, że pokazane są tylko elementy wizualne. Przechodzenie przez drzewo wizualne Silverlight zawiera klasę statyczną VisualTreeHelper wspomagającą badanie drzewa wizualnego. Korzystając z metod GetChild i GetChildrenCount możemy rekurencyjnie przechodzić przez elementy drzewa od dowolnego elementu tak głęboko, jak tylko chcemy. Metoda GetParent pozwala nam śledzić elementy drzewa od danego elementu w górę drzewa do elementu podstawowego drzewa wizualnego, jak widać na wydruku 2.12. Wydruk 2.12 Korzystanie z VisualTreeHelper do przechodzenia przez elementy drzewa od danego elementu do elementu głównego Wynik: System.Windows.Controls.StackPanel System.Windows.Controls.Border System.Windows.Controls.Grid System.Windows.Controls.Grid VisualTree.MainPage XAML: <UserControl x:class="visualtree.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot" Background="White"> <Grid> <Border BorderThickness="1" BorderBrush="Black" Margin="10"> <StackPanel Margin="10">
42 Rozdział 2 Fundamenty XAML <TextBlock x:name="mytextblock" Text="Hello!" /> <TextBlock Text="Lorem ipsum" /> </StackPanel> </Border> </Grid> </Grid> </UserControl> Element początkowy Element równorzędny C#: public MainPage() { InitializeComponent(); Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { DependencyObject o = MyTextBlock; while((o = VisualTreeHelper.GetParent(o))!= null) { Debug.WriteLine(o.GetType().ToString()); } } Zaczynamy w zdarzeniu Loaded Kończymy na elemencie głównym Zaczynamy podróż po drzewie w procedurze obsługi zdarzenia Loaded, ponieważ drzewo nie jest gotowe, dopóki element UserControl nie zostanie załadowany. Wiemy, że droga się kończy, gdy napotkamy element, którego element nadrzędny jest pusty (null) czyli element główny drzewa. Możemy zauważyć, że podczas generowania drzewa obiektów dla całej aplikacji będziemy mieli wiele wystąpień kontrolek, z których każda zawiera elementy o tej samej nazwie. Zakres nazw omawiany w kolejnym temacie zapewnia, że nazwy będą mogły być adresowane w sposób unikalny w całym drzewie obiektów. 2.2.2 Zakres nazw Wcześniej w tym rozdziale widzieliśmy, że możemy definiować właściwość x:name dla elementów w XAML. Pozwala to na odnalezienie kontrolki w kodzie i przeprowadzenie na niej operacji lub obsługiwanie jej zdarzeń. Rozważmy przez chwilę pomysł umieszczenia wielu kontrolek na tej samej stronie, z których każda zawiera elementy posiadające nazwy. Do poradzenia sobie z tą sytuacją XAML wprowadza pojęcie zakresu nazw. Zakres nazw po prostu zapewnia, że nazwy pomiędzy wystąpieniami kontrolek nie będą kolidować ze sobą. Jest to podobny pomysł do podejścia stosowanego przez ASP.NET przy generowaniu nazw kontrolek w celu zapewnienia, że pozostaną unikalne. Wydruk 2.13 pokazuje przykład, gdzie zakres nazw jest konieczny w celu zapobieżenia zduplikowanym nazwom kontrolek.
Drzewa obiektów i zakres nazw 43 Wydruk 2.13 Bez zakresu nazw nazwa MyButton występowałaby kilkukrotnie w tym drzewie XAML: <UserControl x:class="namescopeexample.mynestedcontrol" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="200" Height="150"> <Grid x:name="layoutroot" Background="White"> <Button x:name="mybutton" /> MyButton w elemencie UserControl </Grid> </UserControl> XAML: <UserControl x:class="namescopeexample.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:namescopeexample" Width="400" Height="300"> <StackPanel x:name="layoutroot" Background="White"> <local:mynestedcontrol x:name="control1" /> <local:mynestedcontrol x:name="control2" /> Wiele wystąpień <local:mynestedcontrol x:name="control3" /> </StackPanel> </UserControl> Przy trzech wystąpieniach kontrolki użytkownika na wydruku 2.13, jak parser XAML zapobiega kolizjom nazw pomiędzy wszystkimi przyciskami MyButtons w drzewie obiektów pozwalając przy tym w unikalny sposób odwoływać się do każdego z nich? Poprzez zakres nazw. Jak można by oczekiwać, użycie tej samej nazwy dwukrotnie wewnątrz tego samego zakresu nazw XAML spowodowałoby błąd parsowania. Jest to podobne do błędu w czasie kompilacji, który otrzymalibyśmy, gdybyśmy nadali dwóm zmiennym tę samą nazwę wewnątrz tego samego zakresu w aplikacji C#. UWAGA Wersja Silverlight 2 miała błąd przestrzeni nazw, który objawiał się przy nadawaniu nazwy elementowi wewnątrz wskazówki (tooltip) dołączanej do elementów w kontrolce ItemsControl, takiej jak ListBox. Błąd ten wskazywał, że istnieją zduplikowane nazwy w drzewie obiektów. Zostało to naprawione w wersji Silverlight 3. W praktyce zwykle nie musimy się przejmować zakresami nazw, o ile nie ładujemy i nie przetwarzamy XAML w czasie działania programu korzystając z interfejsu API JavaScript createfromxaml lub zarządzanego interfejsu API XamlReader.Load. Zakresy nazw są tworzone automatycznie podczas wykonywania programu, gdy tworzymy wystąpienia kontrolek. Gdy już rozumiemy pojęcie zakresu nazw, wróćmy do jednej z pozostałych rzeczy, na które natkniemy się w kodzie XAML: składni z nawiasami klamrowymi dla rozszerzeń języka znaczników.
44 Rozdział 2 Fundamenty XAML 2.3 Rozszerzenia XAML i konwertery typów Gdy już znamy strukturę i reguły rządzące plikami XAML, przyjrzyjmy się czemuś, co pozwala nam nieco naginać te reguły: rozszerzeniom. XAML pozwala nam przedstawiać niemal wszystko przy użyciu składni dla elementów- -obiektów i atrybutów-właściwości. Niektóre rzeczy mogą być jednak niewygodne do uzyskania w ten sposób. Z tego powodu XAML zawiera pojęcie rozszerzeń w formie rozszerzeń kodu znacznikowego i konwerterów typów. Silverlight zawiera też pojęcie konwerterów wartości, ale ponieważ jest ono wykorzystywane prawie wyłącznie z wiązaniem, to omówimy je w rozdziale 11. Warto przyswoić sobie oba te pojęcia, aby zrozumieć, co dzieje się, gdy język XAML jest przetwarzany i co oznaczają te nawiasy klamrowe. Chociaż nie możemy obecnie tworzyć swoich własnych rozszerzeń kodu znacznikowego, to konwertery typów dają nam niezwykłe możliwości rozszerzania XAML przy użyciu naszego własnego kodu. Zaczniemy od rozszerzeń kodu znacznikowego, następnie przejdziemy do wykorzystania istniejących konwerterów typów, a później tworzenia swoich własnych konwerterów typów. 2.3.1 Rozszerzenia kodu znacznikowego Podczas przeglądania kodu XAML o różnym stopniu skomplikowania można się natknąć na fragmenty, takie jak Style="{StaticResource MyStyle}" lub Text="{Binding LastName}". Nawiasy klamrowe wskazują, że mamy do czynienia z rozszerzeniem kodu znacznikowego. Rozszerzenia kodu znacznikowego to kod, który może zapewniać wartość właściwości zależnościowej. W pierwszym przykładzie rozszerzenie kodu znacznikowego zapewnia pełny obiekt stylu dla właściwości Style. Nie możemy tworzyć nowych rozszerzeń kodu znacznikowego, ale możemy korzystać z wbudowanego zestawu, który obecnie składa się z rozszerzeń StaticResource, Binding i TemplateBinding. Wydruk 2.14 ilustruje użycie rozszerzeń StaticResource i Binding. Wydruk 2.14 Rozszerzenia kodu znacznikowego Binding i StaticResource w XAML <UserControl x:class="markupextensionexample.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <UserControl.Resources> <Style x:key="textblockstyle" TargetType="TextBlock"> <Setter Property="FontSize" Value="25" /> <Setter Property="Foreground" Value="DarkGray" /> </Style> </UserControl.Resources> <StackPanel x:name="layoutroot"> <TextBlock Text="{Binding LastName}" Zasób Style Rozszerzenie Binding
Rozszerzenia XAML i konwertery typów 45 Style="{StaticResource TextBlockStyle}" /> <TextBlock Text="{Binding FirstName}" Style="{StaticResource TextBlockStyle}" /> <TextBlock Text="{Binding MiddleInitial}" Style="{StaticResource TextBlockStyle}" /> </StackPanel> </UserControl> Wielokrotnie wykorzystany styl W przypadku właściwości Text na wydruku 2.14 rozszerzenie kodu znacznikowego zapewnia wartość z silnika wiązania danych. Wiązanie danych omówimy w rozdziale 11. Rozszerzenia kodu znacznikowego są świetnym sposobem uzyskania jakiejś dodatkowej funkcjonalności z XAML bez konieczności używania rozwlekłej składni obiektowej. Jedną z wad jest to, że nie możemy ich tworzyć sami. Dwa rodzaje rozszerzeń, które możemy tworzyć sami, to konwertery typów i konwertery wartości. 2.3.2 Konwertery typów Konwertery typów są używane w całej platformie.net do obsługi tłumaczenia jednego typu CLR na inny. W szczególności w kontekście XAML konwertery typów są używane do tłumaczenia łańcuchów tekstowych, takich jak Black, na odpowiadające im obiekty.net. W przypadku pokazanym na wydruku 2.15 właściwość Color obiektu SolidColorBrush jest ustawiana przez łańcuch tekstowy Black, który jest konwertowany na kolor o składowych Red=0, Green=0, Blue=0, Alpha=255. Pokazano to na wydruku 2.15. Wydruk 2.15 Konwerter typów w działaniu <UserControl x:class="typeconverterexample.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Grid x:name="layoutroot" Background="Black"> </Grid> Konwerter typu Brush </UserControl> Jest tyle wbudowanych konwerterów typów, że być może nigdy nie będziemy musieli sami pisać nowych. Jednak pozwalają one na rozszerzanie XAML i dlatego zapewniają nam elastyczność pozwalając dokonywać rzeczy, których język XAML mógłby normalnie nie obsłużyć. Tworzenie niestandardowych konwerterów typów Po pierwsze, ponieważ musimy oznaczyć swój typ atrybutem konwertera typów, będziemy musieli mieć dostęp do kodu źródłowego. Jeśli nie mamy dostępu do źródła typu, a możemy określić konwerter tylko dla pojedynczej właściwości swojej własnej klasy, to wystarczy. Różnica jest taka, że konwerter zdefiniowany na poziomie właściwości będzie działał tylko dla tej jednej właściwości w tej jednej klasie, a nie we wszystkich wystąpieniach tego typu we wszystkich właściwościach i we wszystkich klasach.
46 Rozdział 2 Fundamenty XAML Następnie będziemy musieli zdecydować się na format łańcucha tekstowego. Opcje są szeroko otwarte, za wyjątkiem tego, że nie możemy korzystać z nawiasów klamrowych {}, ponieważ inicjują one przetwarzanie rozszerzeń kodu znacznikowego (omówionych wcześniej w tym rozdziale). Wydruk 2.16 pokazuje przykładowy konwerter typu zamieniający łańcuch tekstowy na obiekt Border. Formatem obramowania jest <kolor> <grubość>, gdzie kolor jest nazwą koloru lub kodem koloru złożonym z ośmiu cyfr szesnastkowych, a grubość jest liczbą większą lub równą od zera. Wydruk 2.16 Niestandardowy konwerter typu, który zamienia łańcuch tekstowy na obramowanie (C#) public class BorderTypeConverter : TypeConverter { public override bool CanConvertFrom( ITypeDescriptorContext context, Type sourcetype) { return sourcetype == typeof(string); } Klasa bazowa TypeConverter XAML wymaga tylko łańcuchów tekstowych public override object ConvertFrom( ITypeDescriptorContext context, CultureInfo culture, object value) { string val = value as string; if (val == null) return null; string[] parts = val.split(' '); Rozdzielanie spacjami if (parts.length < 2) return null; Ochrona przed niepoprawnymi łańcuchami tekstowymi SolidColorBrush brush = (SolidColorBrush)XamlReader.Load( "<SolidColorBrush " + "xmlns=" + "'http://schemas.microsoft.com/winfx/2006/xaml/presentation'" + " Color='" + parts[0] + "' />"); Wywołanie double d; double.tryparse(parts[1], out d); Thickness thick = new Thickness(d); Border border = new Border(); border.borderthickness = thick; border.borderbrush = brush; return border; } } Tworzenie obiektu typu Border Przetwarzanie grubości Wynikowy obiekt typu Border XamlReader. Load do przetworzenia koloru Warto zwrócić uwagę, że ten przykład, aby nadawał się do profesjonalnego wykorzystania, wymagałby dodatkowego sprawdzania warunków granicznych i możliwości oddzielania elementów przy pomocy przecinków, a nie tylko spacji.
Rozszerzenia XAML i konwertery typów 47 Aby utworzyć niestandardowy konwerter typów, musimy najpierw zdefiniować klasę dziedziczącą po klasie bazowej TypeConverter. Aby wykorzystywać konwerter typów w XAML, musimy jedynie obsługiwać konwersję z typu string. Konwertery o bardziej ogólnym przeznaczeniu będą obsługiwać dodatkowe typy. Warto zwrócić uwagę na sztuczkę wykorzystaną do pozyskania informacji o kolorze pozwala ona na użycie dowolnej reprezentacji koloru, która może być przetworzona przez parser XAML. XamlReader.Load jest sprytną funkcją, która ma wiele zastosowań, nie tyko do tworzenia gałęzi drzewa obiektów podczas działania aplikacji, ale też do prostego wywoływania parsera, jak to zrobiliśmy tutaj. Niektóre elementy w Silverlight po prostu prościej przetworzyć w XAML niż w kodzie należy do nich między innymi kolor. UWAGA W Silverlight zrozumiałe są tylko niektóre z wielu nazw kolorów, a klasa Color w Silverlight nie ma metody pozwalającej na przetworzenie łańcucha tekstowego w celu uzyskania pozostałych kolorów lub ich przedstawienia w postaci szesnastkowej. Użycie parsera XAML poprzez metodę XamlReader.Load() na wydruku 2.16 pozwala nam zredukować setki wierszy kodu przetwarzającego do pojedynczego wiersza kodu. Klasę XamlReader omówimy dokładniej w dalszej części tego rozdziału. Wydruk 2.17 ilustruje prosty przykład zastosowania naszego niestandardowego konwertera typów. Warto zwrócić uwagę, że ten przykład pokazuje też, jak deklarować właściwość zależnościową coś, co omówimy dokładniej w rozdziale 24. Wydruk 2.17 Prosta klasa, która wykorzystuje nasz niestandardowy konwerter typów public class TestClass : Control { [TypeConverter(typeof(BorderTypeConverter))] public Border Border { get { return (Border)GetValue(BorderProperty); } set { SetValue(BorderProperty, value); } } TypeConverterAttribute public static readonly DependencyProperty BorderProperty = DependencyProperty.Register("Border", typeof(border), typeof(testclass), null); } Atrybut TypeConverterAttribute, który określa konwerter typów do wykorzystania przez tę określoną właściwość w tej klasie, pokazano na wydruku 2.17. Atrybut ten jest nadawany właściwości publicznej, ponieważ będzie to wykorzystywane przez XAML. Konwerter jest deklarowany dla pojedynczej właściwości, więc będzie stosowany tylko tam, a nie do wszystkich wystąpień typu Border. Ważne jest też, aby zwrócić uwagę, że obramowanie nie jest w istocie używane do niczego innego, jak tylko do zilustrowania, jak korzystać z konwertera typów.
48 Rozdział 2 Fundamenty XAML Na koniec wydruk 2.18 pokazuje konwerter typów wykorzystany niejawnie w XAML. Wydruk 2.18 Kod XAML pokazujący niestandardowy konwerter typu Border w użyciu <UserControl x:class="typeconverterexample.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:typeconverterexample"> <Grid x:name="layoutroot"> <local:testclass Border="Red 5" /> </Grid> </UserControl> Konwerter typu w użyciu Ponieważ użyliśmy metody XamlReader.Load, to moglibyśmy łatwo użyć dowolnego prawidłowego łańcucha określającego kolor, takiego jak "LemonCream" lub "#C830019F". Punkty premiowe dla tych, którzy wyłapali aluzję do filmu Star Wars na wydruku 2.18. Kolory w XAML Jeśli ktoś jest przyzwyczajony do korzystania z sześciocyfrowych kolorów szesnastkowych w HTML, to może go dziwić kod koloru #C830019F. Kolory w Silverlight są zwykle przedstawiane jak ośmiocyfrowe liczby szesnastkowe, gdzie pierwsza para cyfr oznacza składnik alfa, a pozostałe trzy pary oznaczają odpowiednio składniki czerwony, zielony i niebieski. W kolorze #C830019F elementy te są następujące alfa: 0xC8, czerwony: 0x30, zielony: 0x01 i niebieski: 0x9F. Składnik alfa jest opcjonalny, więc możemy korzystać z kolorów szesnastkowych w stylu HTML. Dla utrzymania spójności między aplikacjami zalecam stosowanie wartości alfa i używanie wszystkich ośmiu cyfr bez żadnych skrótów. Konwertery typów są świetnym sposobem na rozszerzanie elastyczności XAML o obsługę typów, które tworzymy sami albo nowych przedstawień istniejących typów. Korzystaliśmy z nich w projektach w celu zapewniania wsparcia serializacyjnego dla łańcuchów tekstowych w starszych formatach przechowywanych w bazach danych lub rozszerzania znanych przedstawień istniejących typów. Teraz gdy rozumiemy podstawy XAML i widzieliśmy prosty przykład dynamicznego ładowania XAML w celu przetworzenia łańcucha określającego kolor, przenieśmy się na wyższy poziom i przyjrzyjmy się ładowaniu w trakcie działania aplikacji lub bardziej zaawansowanej zawartości. 2.4 Ładowanie XAML podczas działania programu Na wydruku 2.16 widzieliśmy krótki przykład ładowania XAML podczas działania programu przy użyciu metody XamlReader.Load. Rozwińmy ten temat, aby zrobić coś więcej, niż tylko prostą konwersję kolorów podstawowych. Możemy korzystać z dynamicznie ładowanego
Ładowanie XAML podczas działania programu 49 kodu XAML w celu tworzenia całych fragmentów drzewa obiektów podczas działania programu. Może być to przydatne do obrazowania zawartości generowanej przez użytkownika, na przykład kształtów rysowanych na ekranie i zapisywanych w bazie danych lub do tworzenia bardzo dynamicznych kontrolek. Proces ładowania XAML podczas działania programu jest niewiarygodnie łatwy. Musimy tylko polegać na klasie XamlReader, która należy do przestrzeni nazw System.Windows.Markup. Ta klasa pozwala nam przetwarzać kod XAML i konwertować go na obiekt przechowywany w pamięci. Ten obiekt może być tworzony przez statycznie widoczną metodę o nazwie Load. Metoda ta bierze łańcuch tekstowy zawierający kod XAML i konwertuje go na odpowiedni obiekt. Następnie możemy wstawiać ten obiekt do innego obiektu UIElement. Wydruk 2.19 pokazuje cały ten proces w działaniu. Wydruk 2.19 Ładowanie i przetwarzanie XAML w trakcie działania programu Wynik: XAML: C#: <UserControl x:class="xamlreaderexample.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot"> </Grid> </UserControl> public MainPage() { InitializeComponent(); Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { var element = CreateRectangle(); LayoutRoot.Children.Add(element); } Dodanie do drzewa private Rectangle CreateRectangle() {
50 Rozdział 2 Fundamenty XAML StringBuilder xaml = new StringBuilder(); string ns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"; xaml.append("<rectangle "); xaml.append(string.format("xmlns='{0}'", ns)); xaml.append(" Margin='5 10 5 15'"); xaml.append(" Fill='Orange'"); xaml.append(" Stroke='Black' />"); Deklaracja przestrzeni nazw var rectangle = (Rectangle) XamlReader.Load(xaml.ToString()); XamlReader.Load return rectangle; } Ten przykład dynamicznie tworzy prostokąt i dodaje go do drzewa obiektów. Kod w metodzie CreateRectangle po prostu buduje łańcuch tekstowy z kodem XAML podobnie, jak byśmy to robili sami w zwykłym pliku.xaml. Należy zwrócić uwagę, że musimy określić przestrzenie nazw używane przez każdy fragment XAML, który będziemy przekazywać do metody XamlReader.Load. Kod, który dodaje wygenerowany kod XAML do drzewa obiektów, można zobaczyć wewnątrz procedury obsług zdarzenia. Możemy oczywiście zrobić znacznie więcej z danym elementem, niż tylko dodać go do LayoutRoot. Wydruk 2.20 ilustruje, jak możemy wziąć kod XAML i zintegrować go z przedstawieniami elementów XAML w kodzie zarządzanym w celu utworzenia wielu wystąpień prostokąta. Wydruk 2.20 Mieszanie dynamicznego XAML z kodem Wynik: XAML: <UserControl x:class="xamlreaderexample2.mainpage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <Grid x:name="layoutroot"> </Grid> </UserControl>
Narzędzia do pracy z XAML 51 C#: public MainPage() {... } void MainPage_Loaded(object sender, RoutedEventArgs e) { for (int i = 0; i < 4; i++) { RowDefinition def = new RowDefinition(); LayoutRoot.RowDefinitions.Add(def); Rectangle rect = CreateRectangle(); Grid.SetRow(rect, i); LayoutRoot.Children.Add(rect); } } private Rectangle CreateRectangle() {... } Ustawienie wiersza siatki Pętla tworząca cztery wystąpienia W tym przykładzie tworzymy w pętli cztery wystąpienia obiektu prostokąta. Następnie dynamicznie tworzymy definicje wierszy siatki (patrz rozdział 6) w kodzie zamiast w przetwarzanym XAML i przypisujemy je poprzez właściwości połączone do naszego obiektu prostokąta. To pokazuje mieszankę przedstawień w CLR elementów, takich jak wiersze siatki, i przedstawień w kodzie XAML elementów, takich jak prostokąt. W praktyce rzadko będziemy tworzyć elementy wizualne w kodzie, za wyjątkiem specyficznych okoliczności, ale dostępna jest taka elastyczna możliwość. Na tym kończymy omawianie podstawowych pojęć XAML. Następnie przyjrzymy się kilku narzędziom, które możemy wykorzystać do efektywniejszej pracy z XAML. 2.5 Narzędzia do pracy z XAML Jak na razie przyglądaliśmy się wielu surowym plikom XAML. Podczas pracy nad aplikacjami Silverlight będziemy często przechodzić tam i z powrotem pomiędzy surowym kodem XAML a jakimś rodzajem edytora wizualnego lub obszaru projektowego. Oto kilka narzędzi dostępnych do pracy z plikami XAML w Silverlight: Visual Studio 2010 Wersja Visual Studio 2008 zapewnia świetny edytor XAML, ale dość bezużyteczny obszar projektowy i jest ograniczona do wersji Silverlight 2 i 3. Visual Studio 2010 zawiera w pełni funkcjonalny obszar projektowy Silverlight, który obsłuży większość potrzeb programisty i zawiera pełną obsługę wersji Silverlight 3
52 Rozdział 2 Fundamenty XAML i 4. Jeśli chcemy wykonywać więcej prac typu projektowego, w tym dokładnie kontrolować interfejs użytkownika, animacje, stany, zachowania i przejścia, to możemy wykorzystać Expression Blend. Expression Blend Wyłącznym powodem istnienia Expression Blend jest edycja XAML. Jest to główny edytor XAML zarówno dla profesjonalnych projektantów, jak i dla kreatywnych programistów. Podczas gdy ktoś przyzwyczajony do wpisywania kodu znacznikowego może przechodzić tam i z powrotem pomiędzy edytorem XAML a obszarem projektowym, to w Blend niewiele jest rzeczy, których nie da się osiągnąć przy pomocy samych narzędzi projektowych. Kaxaml Czasami nie jest nam potrzebny tak rozbudowany edytor, jak Visual Studio lub Expression Blend. Kaxaml jest lekkim edytorem XAML stworzonym przez Robby ego Ingebretsena. Kaxaml można pobrać za darmo z witryny www.kaxaml.com. Eclipse Jeśli ktoś chce korzystać swobodnie z innych platform, takich jak Mac, to może wykorzystywać do edycji plików XAML narzędzia Silverlight dla Eclipse, dostępne pod adresem www.eclipse4sl.org. Setki innych narzędzi obsługują eksport lub import XAML. Zwykle są to narzędzia graficzne, dodatki do istniejących narzędzi graficznych, takich jak Adobe Illustrator lub narzędzi 3D. Wiele z nich jest głównie ukierunkowana na WPF, ale przynajmniej częściowo współpracują z Silverlight. 2.6 Podsumowanie Programowanie w Silverlight opiera się na kodzie i znacznikach. Aby maksymalnie wykorzystać tę platformę, warto dowiedzieć się, jak stosować możliwości zapewniane przez XAML zachowując przy tym równowagę pomiędzy tym, co piszemy w kodzie, a tym, co umieszczamy w znacznikach. Poznanie języka znaczników pozwoli nam skorzystać z narzędzi do szybkiego tworzenia świetnych interfejsów użytkownika, pracować efektywnie w zespole obejmującym projektantów i programistów oraz pomoże nam wymusić oddzielenie widoku od reszty architektury aplikacji. Zrozumienie podstaw XAML jest niezbędne dla maksymalnego skorzystania z dalszej części tej książki i samej technologii Silverlight. W dalszych rozdziałach rozwiniemy omówione tu zagadnienia, obejmujące tematy, takie jak pędzle, kształty, kontrolki, animacje i wszystkie inne elementy, które sprawiają, że Silverlight jest tak świetną platformą prezentacyjną. W następnym rozdziale omówimy wtyczkę Silverlight i sposób korzystania z niej do tworzenia aplikacji działających wewnątrz przeglądarki i poza przeglądarką.
3 Model aplikacji i wtyczka Silverlight Ten rozdział omawia Model aplikacji Silverlight Tworzenie kontrolki wtyczki Silverlight w przeglądarce Aplikacja jest terminem ogólnym, który może oznaczać różne rzeczy dla różnych ludzi. Można kwestionować, jaki poziom funkcjonalności, zaawansowania lub innej miary jest potrzebny, zanim coś będzie można nazwać aplikacją. Na przykład, czy gadżet paska bocznego w Windows do śledzenia pogody jest aplikacją? A co z Notatnikiem? Kod dla gadżetu paska bocznego jest prawie na pewno bardziej skomplikowany niż kod Notatnika, ale większość ludzi uważałoby Notatnik za aplikację, a gadżet paska bocznego no cóż za gadżet. Uczestnicząc w społeczności Silverlight przy wielu okazjach byłem pytany, jak nazywać tę rzecz, którą wtyczka Silverlight ładuje do przeglądarki. Odpowiedź zależy od kontekstu pytania i natury tej rzeczy. W tym rozdziale porozmawiamy o aplikacjach Silverlight. W kontekście tego rozdziału będę stosować termin aplikacja w technicznym sensie tego słowa: jako skompilowany, możliwy do uruchomienia projekt Silverlight. Aplikacja może być tak mała, jak drobny element menu lub reklama na stronie WWW albo tak skomplikowana, jak niektóre z narzędzi Microsoft lub Adobe, z których korzystałem przy pisaniu tej książki. Pozostawimy otwartym pytanie, kiedy coś można nazywać aplikacją, abyśmy mieli o czym debatować na spotkaniach programistów.
54 Rozdział 3 Model aplikacji i wtyczka Silverlight Niezależnie od naszych własnych, indywidualnych definicji aplikacji, aplikacja Silverlight składa się z pliku.xap ze skompilowanym kodem, informacji o punkcie początkowym, być może kilku zasobów i hosta dla wtyczki Silverlight. Jak widzieliśmy w rozdziale 1, możemy szybko zacząć pracę z Silverlight bez dokładnego zrozumienia tych pojęć dzięki świetnym szablonom zapewnianym przez Microsoft. Ale jako programiści mamy naturalną ciekawość, aby dokładniej dowiedzieć się, co się dzieje, gdy zawartość Silverlight pojawia się na stronie WWW, ponieważ wiedza ta będzie nam potrzebna, gdy nasze aplikacje osiągną większy poziom skomplikowania, a poza tym jest to interesujące. Podstawowe informacje, na których będziemy bazować w pozostałych częściach tej książki, dotyczą modelu aplikacji Silverlight i wtyczki Silverlight. 3.1 Model aplikacji Silverlight Aplikacje Silverlight składają się co najmniej z jednej lub kilku skompilowanych, dynamicznie dołączanych bibliotek (DLL).NET i pliku manifestu, które są wszystkie skompresowane do pliku zwanego XAP (wymawiane zap ). Wszystko to jest ładowane do wtyczki podczas uruchamiania aplikacji, a następnie wykonywane od określonego punktu początkowego aplikacji. Plik.xap jest kluczowym mechanizmem wdrożeniowym dla wszystkich aplikacji Silverlight w kodzie zarządzanym. Gdy mówimy o wdrażaniu aplikacji Silverlight, to tak naprawdę mówimy o dwóch sprawach: Dostarczeniu pliku.xap do klienta poprzez jakiś identyfikator URI Zainicjowaniu wtyczki Silverlight na stronie WWW lub w procesie uruchamiającym aplikację poza przeglądarką To tyle. Nie ma dodatkowej instalacji, pliku.msi do zainstalowania, żadnych wpisów do rejestru, żadnych komunikatów z prośbą o podwyższenie uprawnień (chyba że sami zażądamy podwyższonych praw). Chodzi o jak najbardziej bezproblemowe dostarczenie zawartości do użytkownika końcowego i zainicjowanie jej we wtyczce przeglądarki. Niuanse działania tego procesu uważam za szczególnie interesujące. Gdy po raz pierwszy poznawałem ASP.NET w czasach, gdy 17-calowy monitor zajmował całe biurko, zawierał więcej szkła niż samochód i ważył około 100 kg jedną z rzeczy, które mnie najbardziej ciekawiły, był cykl rozruchowy i kolejność zdarzeń podczas żądania strony. Jeśli chcemy zrozumieć, jak korzystać z określonej platformy aplikacyjnej, to naprawdę musimy wiedzieć, jak będzie ona uruchamiać naszą aplikację, kiedy rzeczy są ładowane, kiedy obrazowane i jak są podejmowane kluczowe decyzje musimy poznać proces rozruchowy aplikacji. 3.1.1 Proces rozruchowy aplikacji Co się dzieje, gdy wejdziemy na stronę WWW, która zawiera aplikację Silverlight? Proces rozruchowy aplikacji jest pokazany na rysunku 3.1. Ten diagram zawiera szczegóły dotyczące
Model aplikacji Silverlight 55 wersji Silverlight od 1 do 4, ale nie uwzględnia języków dynamicznych. Krok XAML czy XAP decyduje, czy mamy do czynienia ze starym modelem Silverlight 1.0, czy aktualnym modelem Silverlight 2+. Ta decyzja opiera się na połączeniu źródła aplikacji (plik.xaml lub.xap) i określonej właściwości type dla wtyczki. Przeglądarka ładuje HTML i pliki Nie Wyświetl interfejs instalacyjny Tak Xaml XAML czy XAP? Xap Wymagana wersja zainstalowana? Niestandardowy ekran tytułowy? Tak Załaduj kod XAML niestandardowego ekranu tytułowego i podłącz zdarzenia Pokaż domyślny ekran tytułowy Pobierz XAP Wczytaj manifest aplikacji Załaduj podzespoły Zainicjuj klasę punktu wejścia Wywołaj procedury obsługi zdarzeń JavaScript Wywołaj procedurę obsługi uruchomienia aplikacji Załaduj wizualny element główny Zobrazuj/Uruchom aplikację Rysunek 3.1 Proces uruchamiania Silverlight. Ten schemat opisuje proces ładowania od załadowania strony HTML aż do wykonania zdarzeń dla głównego elementu wizualnego aplikacji Silverlight.
56 Rozdział 3 Model aplikacji i wtyczka Silverlight CoreCLR Silverlight 2+ wykorzystuje wersję środowiska uruchomieniowego Common Language Runtime (CLR) znaną jako CoreCLR. Jest to wersja.net CLR, która została zoptymalizowana pod kątem rozmiaru i wykorzystania w rozbudowanych aplikacjach internetowych (RIA). CoreCLR ma wspólny kod z pełnym środowiskiem uruchomieniowym.net CLR, jeśli chodzi o elementy podstawowe, takie jak system plików, zoptymalizowany pod kątem stacji roboczych odśmiecacz i kompilator just-in-time (JIT). Te optymalizacje rozmiaru i inteligentne decyzje dotyczące tego, co jest, a co nie jest potrzebne dla aplikacji klienckich RIA, pozwalają wtyczce Silverlight włącznie z środowiskiem CoreCLR zmieścić się mniej więcej w całkowitym rozmiarze około 5 MB. Więcej szczegółów na temat CoreCLR można znaleźć w artykule MSDN autorstwa Andrew Pardoe a pod adresem http://msdn.microsoft.com/en-us/magazine/ cc721609.aspx. Kropkowana linia pomiędzy JavaScript a procedurami obsługi zdarzeń w kodzie zarządzanym pojawia się ze względu na to, że dla zdarzenia ładowania aplikacji możemy mieć aktywne zarówno procedury obsługi zdarzenia w JavaScript, jak i w kodzie zarządzanym, choć zwykle nie będziemy z tego korzystać. Kolejność, w jakiej zostaną wywołane w stosunku do siebie, nie jest gwarantowana. Niektóre dodatkowe części tego procesu nie są pokazane na rysunku 3.1, ale pomimo to są interesujące. Na przykład, gdy wtyczka Silverlight ustali, że będzie miała do czynienia z plikiem.xap z kodem zarządzanym, to ładuje środowisko uruchomieniowe Silverlight.NET CLR (CoreCLR) do przestrzeni pamięciowej przeglądarki. Oczywiste w tym wszystkim staje się to, że najważniejszym elementem w tym procesie jest sama aplikacja Silverlight: plik.xap. 3.1.2 XAP Aplikacja Silverlight w kodzie zarządzanym jest podczas budowania pakowana do pliku.xap. Plik.xap jest po prostu plikiem ZIP i można sprawdzić jego zawartość zmieniając jego rozszerzenie na.zip i otwierając go w dowolnym programie archiwizującym obsługującym format ZIP. Zawartość typowego pliku.xap jest pokazana na rysunku 3.2. Ten skompresowany plik będzie zawsze zawierał plik manifestu o nazwie AppManifest. xaml. Ponadto zawsze będzie tam plik.dll, który służy jako punkt wejścia do aplikacji Silverlight. Ta aplikacja może wymagać innych bibliotek Silverlight, informacji o połączeniach z usługami lub innych typów zawartości. Elementy zawartości i dodatkowe biblioteki mogą znajdować się w pliku.xap aplikacji lub być pobierane w trakcie jej działania; w każdym razie reprezentują elementy, od których aplikacja jest zależna. Ponieważ plik.xap jest skompresowanym archiwum kompatybilnym z formatem ZIP, to możemy zmienić jego zawartość i ponownie skompresować go po zmianach. Powodem do tego może być dołączenie zaktualizowanych odwołań do usług (na przykład przy przejściu
Model aplikacji Silverlight 57 z środowiska testowego do środowiska produkcyjnego) lub zmiana innych plików konfiguracyjnych XML specyficznych dla środowiska lub klienta, zmiana zasobów wykorzystywanych przez aplikację lub innych elementów. MyApp.xap AppManifest.xaml MyApp.dll Dodatkowe biblioteki (.dll) Zapakowana zawartość (obrazy, multimedia) ServiceReferences.ClientConfig Rysunek 3.2 Struktura typowego pliku.xap pokazująca typy plików, które są w nim normalnie zawarte. Można też nieco zmniejszyć rozmiar pliku.xap ponownie kompresując go przy użyciu wydajnego narzędzia ZIP, takiego jak 7-Zip, kosztem nieco wolniejszego procesu dekompresji i czasu uruchamiania aplikacji na starszych komputerach. Może to być ważne w sytuacjach, gdzie przepustowość sieci jest znacznie ograniczona. Plik.xap zawiera wiele różnych plików. Jednym z nich jest plik manifestu aplikacji informujący Silverlight, jakie inne pliki są zawarte w.xap i gdzie znaleźć punkt wejścia do aplikacji. 3.1.3 Plik manifestu aplikacji Plik manifestu odpowiada za opisanie aplikacji Silverlight środowisku uruchomieniowemu Silverlight. Plik ten jest tworzony podczas budowania aplikacji przez Visual Studio i zwykle nie jest ręcznie edytowany. Środowisko uruchomieniowe Silverlight odczytuje plik AppManifest.xaml począwszy od elementu głównego Deployment. Ten element zawiera dwa atrybuty, które informują środowisko uruchomieniowe Silverlight, jak ma uruchamiać aplikację Silverlight, co pokazano tutaj: <Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="MyApp" EntryPointType="MyApp.App" RuntimeVersion="4.0.50401.0"> <Deployment.Parts> <AssemblyPart x:name="myapp" Source="MyApp.dll" /> </Deployment.Parts> </Deployment> Ten przykład pokazuje podstawowy plik manifestu, który wykorzystuje atrybuty EntryPointAssembly i EntryPointType przy uruchamianiu aplikacji Silverlight. Pierwszy atrybut EntryPointAssembly będzie zawsze odwoływał się do jednego z elementów AssemblyPart w sekcji Deployment.Parts. Drugi atrybut EntryPointType wyjaśnia, która klasa powinna zostać