ASP.NET Starter Kit Maja Ciemienga Strony wzorcowe i motywy graficzne w ASP.NET 2.0 Tworząc aplikacje internetowe przy użyciu Visual Studio.NET 2003 po pewnym czasie pojawia się potrzeba dodania własnych komponentów w celu spełnienia wymogów projektowych. Użytkownikowi nie wystarczają jedynie wbudowane funkcjonalności. Kolokwialnie rzecz ujmując apetyt rośnie w miarę jedzenia. Możliwość skorzystania z gotowych rozwiązań wbudowanych w środowisko programistyczne (j.ang. IDE Integrated Development Environment) bardzo często oznacza oszczędność czasu i środków finansowych przeznaczonych na realizację zamierzeń produkcyjnych. ASP.NET 2.0 przychodzi w sukurs zapotrzebowaniu rynkowemu i dostarcza wiele pożytecznych, elastycznych w modyfikacji rozwiązań. Dwa z nich, będące motywem przewodnim niniejszego artykułu, to strony wzorcowe (j.ang. Master Pages) oraz motywy graficzne (j.ang. themes). Przyczyną takiego zestawienia jest istnienie pomiędzy nimi silnego powiązania. Obydwa poruszają aspekt estetyczny interfejsu użytkownika, pozwalają zadbać o zachowanie spójności wizualnej aplikacji, kształtować odpowiedni wygląd i odczucie (j.ang. look and feel) witryny. Strony wzorcowe Konieczność powielania pewnych części strony WWW, definiowania obszarów takich jak nagłówek, menu, stopka wymogła zapotrzebowanie na proste rozwiązanie zapewniające tą funkcjonalność. W ASP.NET 1.1 dominowała żmudna technika kopiuj-wklej kodu, tekstu, kontrolek użytkownika. Jakże to pracochłonne i nieoptymalne! Najkorzystniej na tym tle przedstawia się możliwość dodania w kodzie HTML odsyłacza do oddzielnego pliku skupiającego wszystkie wspólne elementy. Tak jak postępuje się w przypadku styli kaskadowych i skryptów JavaScript. Spełnienie marzeń to opcja podglądu efektu końcowego podczas edycji strony w widoku projektowym (j.ang. design view) IDE. Oczekiwania te w ASP.NET 2.0 spełnia magiczny termin - strony wzorcowe (j.ang. Master Pages). Udogodnienie to wprowadzono dopiero w.net Framework 2.0 w związku z równoczesnym pojawieniem się klas cząstkowych (j.ang. Autorka pracuje na stanowisku głównego programisty ASP modelu w firmie Eracent Inc, gdzie zajmuje się tworzeniem aplikacji i usług sieciowych opartych na ASP.NET. Posiada tytuł MVP w kategorii Visual Developer ASP/ASP.NET. Ponadto bierze aktywny udział w społeczności skupiającej pasjonatów Microsoft.NET jako redaktor developers.pl, założyciel Warszawskiej Grupy.NET oraz przedstawiciel INETA w Polsce. Kontakt z autorką: lizardsis@gmail.com Wszystkie przykłady zaczerpnięto ze strony Warszawskiej Grupy.NET http://wawadotnet.aspweb.cz mojego autorstwa. partial classes). Strona wzorcowa umożliwia zgromadzenie w jednym miejscu elementów takich jak tekst, menu, kontrolki HTML, kontrolki serwerowe ASP.NET oraz kod obsługujący zdarzenia wywoływane przez użytkownika. Mogą z niej korzystać zarówno pojedyncze strony w aplikacji ASP.NET, jak i ich grupy. Reprezentuje ją plik z rozszerzeniem.master z opcjonalnie dołączonym plikiem z kodem (j.ang. code-behind). Główna różnica pomiędzy Master Page a standardową stroną ASP.NET to zamiana dyrektywy @Page na @Master przyjmującą postać wg. wzoru: <%@ Master atrybut="wartość" [atrybut =" wartość "...] %> W.NET Framework 2.0 Master Page to klasa w przestrzeni nazw System.Web.UI dziedzicząca klasę UserControl. Dzięki temu w dyrektywie @Master stosuje się większość atrybutów dyrektywy @Control. Klasa MasterPage nie implementuje interfejsu IHttpHandler, a zatem próba jej bezpośredniego wywołania, spowoduje wystąpienie błędu. Stworzenie strony wzorcowej w środowisku programistycznym Visual Studio.NET 2005 to prozaiczna czynność. W tym celu należy wybrać z menu Website-> Dodaj Nowy Element (j.ang. Add New Item) lub skorzystać ze skrótu Ctrl+Shift+A, a następnie wskazać Master Page (patrz Rysunek 1). Aby dodać dodatkowy plik z kodem do obsługi zdarzeń, należy zaznaczyć opcję: Umieść kod w oddzielnym pliku (j.ang. Place code in separate file). Przykład widoku projektowego strony wzorcowej site.master ilustruje Rysunek 2, zaś definiujący towarzyszący jej kod HTML przedstawiono w Listingu 1. Należy zwrócić uwagę na dyrektywę @Master oraz część środkową reprezentowaną przez tzw. ContentPlaceHolder. Jak widać na Rysunku 2, wzorzec zawiera między innymi nagłówek z menu oraz stopkę. Polecane artykuły A Sneak Peak at MasterPages in ASP.NET 2.0 Scott Mitchell http://aspnet.4guysfromrolla.com/articles/010505-1.aspx Build Web Sites Using Master Pages, Dino Esposito http://www.ftponline.com/vsm/2004_08/ magazine/columns/aspnet/ Dokmentacja dla produktów Visual Studio 2005 i SQL Server 2005 http://msdn2.microsoft.com/en-us/library/ default.aspx 20 www.sdjournal.org Software Developer s Journal Extra! 20
w tym zdarzeniu w cyklu życia strony następuje łączenie Content Page z Master Page. Przeważnie dynamiczne wskazanie strony wzorcowej następuje w metodzie Page_PreInit: void Page_PreInit(Object sender, EventArgs e){ this.masterpagefile = "~/site.master"; Rysunek 1. Dodawanie Master Page w Visual Studio.NET 2005 ContentPlaceHolder W Listingu 1 pojawił się jeden z bardzo istotnych elementów powiązanych ze stronami wzorcowymi ContentPlaceHolder. Jest to jedna z serwerowych kontrolek w ASP.NET służąca do przechowywania treści, definiowania obszarów na stronie wzorcowej mogących ulec nadpisaniu przez strony z niej korzystające. Pojedyncza strona wzorcowa może zawierać dowolną ilość kontrolek tego typu. Oznacza to, że możemy podzielić wzorzec na wiele ruchomych, wymienialnych części. Content Page Każdą stronę ASP.NET czyli klasę System.Web.UI.Page korzystającą ze strony wzorcowej określa się terminem Content Page. Content Page to strona z zawartością, strona definiująca treść, która zostanie umieszczona w odpowiednich pojemnikach na treść w stronie wzorcowej. Gdzie następuje odpowiednie powiązanie pomiędzy poszczególnymi kontrolkami ContentPlaceHolder w MasterPage, a tą treścią? W Content Page wykorzystuje się kolejną serwerową kontrolkę Content. Jedną z jej właściwości jest ContentPlaceHolderID informujący o identyfikatorze kontrolki ContentPlaceHolder, której zawartość będzie podmieniona. Content Page z Master Page Powiązanie Content Page z Master Page można dokonać korzystając z jednego z trzech sposobów. Przede wszystkim w dyrektywie @Page powinno się dodać atrybut MasterPageFile wskazujący na fizyczne umiejscowienie strony wzorcowej, z której zamierzamy skorzystać, np.: <%@ Page MasterPageFile="~/site.master" %> Kolejna deklaratywna metoda dodania strony wzorcowej do wielu stron.aspx w obrębie całej aplikacji lub konkretnego katalogu to umieszczenie w podsekcji system.web w web.config, w ramach znacznika pages, atrybutu master przyjmującego jako wartość nazwę odpowiedniej strony wzorcowej, np.: <configuration><system.web> <pages master="site.master" /> </system.web></configuration> Należy zauważyć, że lokalnie dodana strona wzorcowa przesłania globalnie zdefiniowaną. Istnieje również opcja powiązania Master Page z Content Page w sposób dynamiczny w kodzie. Służy do tego właściwość strony MasterPageFile nazwa pliku definiującego stronę wzorcową. Jej użycie jest możliwe jedynie przed wystąpieniem etapu inicjalizacji strony z zawartością, gdyż W Visual Studio.NET 2005 przy dodawaniu nowej strony (j.ang. Web Form) można zaznaczyć opcję Wybierz stronę wzorcową (j.ang. Select Master Page), co pokazuje Rysunek 3. Po naciśnięciu przycisku OK. należy wybrać Master Page (patrz Rysunek 4) i ponownie zatwierdzić przyciskiem OK. Używając najnowszej wersji środowiska programistycznego Visual Studio przy tworzeniu ContentPage, poszczególne (nieedytowalne) elementy Master Page są widoczne w widoku projektowym (patrz Rysunek 5). Kod HTML reprezentujący tą stronę zajmuje zaledwie dwie linijki: <%@ Page Language="C#" MasterPageFile="~/site.master" Title="Untitled Page" %> <asp:content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> </asp:content> Zagnieżdżanie stron wzorcowych W przypadku zaawansowanych, skategoryzowanych portali zwykle zachodzi potrzeba zagnieżdżania stron wzorcowych. Jest to możliwe dzięki temu, że klasa MasterPage posiada także właściwość MasterPageFile. Deklaratywne dodanie nadrzędnej strony wzorcowej wygląda następująco: <%@ Master MasterPageFile="~/site2.master" %> W zagnieżdżonych stronach wzorcowych można definiować kontrolki Content. Podrzędna strona wzorcowa staje się stroną z zawartością (Content Page) w stosunku do nadrzędnej. Kompatybilność z przeglądarkami Aby zapewnić kompatybilność z różnymi rodzajami przeglądarek, zwykle tworzy się oddzielnie kilka stron wzorcowych dla Internet Explorer a, Mozilli i Opery. W jaki sposób poinformować ContentPage, którą wersje ma wybrać w czasie generowania HTML? Dzięki możliwości zastosowania deklaratywnej składni w ASP.NET 2.0 wystarczy atrybut master poprzedzić nazwą przeglądarki i przypisać do niego odpowiednią Master Page np: <%@ Page ie:master="site.master mozilla:master="mozilla.master" opera:master= opera.master... %> Dostęp do elementów Master Page z poziomu Content Page Czasami istnieje potrzeba modyfikacji elementów zdefiniowanych w stronie wzorcowej z poziomu strony z niej korzystającej. Aby dotrzeć do składników klasy MasterPage, można użyć właściwości Master w Content Page zwracającej referencję do odpowiedniego obiektu. Innym sposobem uzyskania dostępu do publicznych właściwości, metod czy kontrolek konkretnej strony wzorcowej jest dodanie dyrektywy @ MasterType w stronie podrzędnej, np: <%@ MasterType virtualpath="~/ site.master"%> Dyrektywa @ MasterType, podobnie jak dyrektywa @Reference, może zawierać jeden Software Developer s Journal Extra! 20 www.sdjournal.org 21
ASP.NET Starter Kit Listing 1. Kod HTML przykładowej strony wzorcowej <%@ Master Language="C#" AutoEventWireup="true" CodeFile="site.master.cs" Inherits="site" %> <%@ Register Src="controls/top.ascx" TagName="top" TagPrefix="uc1" %> <html xmlns="http://www.w3.org/1999/xhtml" > <head id="head1" runat="server"> <title>warszawska Grupa.NET</title> <link href="default.css" type="text/css" rel="stylesheet" /> </head> <body> <form id="form1" runat="server"> <table class="maintbl" cellspacing="0" style="height: 473px" > <td class="a1" colspan="2"></td> <td class="a2" align="right" style="width: 39%"> <asp:image runat="server" ID="imgA2" ImageUrl="~/images/logo.gif" /></td > <td align="right"> </td> <td class="a3" rowspan="2" style="width: 39%" > <asp:imagebutton CssClass="imgbtnA3" CausesValidation="false" runat=server ID="imgbtnA3" ImageUrl="~/images/photo.gif" /> </td> <td class="a4" ><div class="a4div" id="a4div" runat=server style="text-align: justify"> Witamy serdecznie wszystkich zainteresowanych na stronie Warszawskiej Grupy.NET. Naszym celem jest zgromadzenie wysoko wyspecjalizowanej grupy zawodowej doskonalącej wiedzę w Microsoft.NET. Zapraszamy do przyłączenia się i wzięcia udziału w najbliższym spotkaniu. </div></td> <td class="a5" align="left" > <uc1:top ID="Top1" runat="server" /></td> <td class="a1" colspan="2" rowspan="" ></td> <td colspan="2" rowspan="" > <asp:contentplaceholder id="contentplaceholder1" runat="server"> </asp:contentplaceholder> </td> <td colspan="2" > <table cellpadding="0" cellspacing="0" class="c1" <td align="center"> 2006 WGdotNET - Warszawska Grupa.NET<br/> powered by <a class="white" href="mailto:lizardsis@gmail.com">lizardsis </a> / designed by Robson </td> </table> </td> </table> </form> </body></html> z dwóch atrybutów: TypeName lub VirtualPath. TypeName wskazuje nazwę klasy, do której aktywna strona będzie się odwoływać, natomiast VirtualPath przypisuje się fizyczną lokalizację strony wzorcowej. W celu znalezienia konkretnej kontrolki w stronie wzorcowej używa się publicznej funkcji FindControl klasy MasterPage. W Content Page uzyskuje się do niej referencję poprzez właściwość Master. Przykładowo, aby z poziomu klasy podrzędnej w stosunku do strony wzorcowej znaleźć kontrolkę ContentPlaceHolder o identyfikatorze ContentPlaceHolder1 z klasy nadrzędnej, korzysta się z funkcji FindControl: ContentPlaceHolder mpcontentplaceholder = (ContentPlaceHolder) Master.FindControl("ContentPlaceHolder1"); Kolejny przykład dotyczy zmiany tekstu z poziomu Content- Page etykiety lblmaster znajdującej się w stronie wzorcowej. Standardowy wartość własności Text wspomnianej etykiety to Zmień mnie: <asp:label runat=server Text= Zmień mnie id= lblmaster /> Najpierw w MasterPage należy zdefiniować właściwość tylko do zapisu ZmienTekst: public partial class site : System.Web.UI.MasterPage {... public string ZmienTekst{... set{ lblmaster.text = value; a następnie do ContentPage np. o nazwie Default.aspx dodać dyrektywy MasterType oraz Page: <%@ Page Language="C#" AutoEventWireup="true" MasterPageFile="~/site.master" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ MasterType VirtualPath="~/site.master" %> Etykiecie lblmaster np. w zdarzeniu Page_Load można przypisać 22 www.sdjournal.org Software Developer s Journal Extra! 20
ASP.NET Starter Kit Rysunek 2. Widok projektowy strony wzorcowej dowolną wartość: protected void Page_Load(object sender, System.EventArgs e){ Master.ZmienTekst = "Jestem w Content Page"; Zastosowanie stron wzorcowych nie jest skomplikowane, a ich nieoceniona użyteczność w zakresie zapewnienia przejrzystości wizualnej sprawia, że należy się zapoznać z tym zagadnieniem przy tworzeniu aplikacji webowych w ASP.NET. Kolejnym nowym rozwiązaniem w.net Framework 2.0 są motywy graficzne. Motywy graficzne Z reguły w aplikacji webowej ASP.NET używa się na każdej stronie podobnych czcionek, krojów pisma, kolorów czy styli zdefiniowanych dla poszczególnych kontrolek. Wobec tego można wyodrębnić wspólne elementy szaty graficznej. ASP.NET 2.0 poprzez tzw. motywy graficzne (j.ang. themes) udostępnia nowy sposób definicji styli dostępnych dla wszystkich stron i ich elementów. W porównaniu z kaskadowymi arkuszami styli motywy posiadają dużo więcej możliwości. Są swoistymi paczkami pozwalającymi na dodanie na poziomie aplikacji, strony czy kontrolki serwerowej odpowiedniego stylu CSS, obrazków i skórek (j.ang.skins). Tworzenie własnego motywu Aby utworzyć własny motyw, należy stworzyć katalog App_ Themes w katalogu głównym aplikacji. W tym celu w Visual Studio.NET 2005 należy nacisnąć prawym przyciskiem myszy na projekcie i wybrać opcję Dodaj Folder (j.ang.add Folder) ->Motyw,co zilustrowano na Rysunku 6. Dla każdego z motywów należy dodać oddzielny katalog w folderze App_Themes. Zazwyczaj definiuje się kilka motywów. Jest Rysunek 4. Wybieranie strony wzorcowej to związane z występowaniem różnych kategorii użytkowników, ich preferencji, zmian pór roku itp. Każdy motyw może zawierać: skórki, pliki css, obrazki. Karnacja w motywie Skórka, inaczej karnacja (z j.ang. skin) jest to, w terminologii.net, definicja styli stosowanych do kontrolek serwerowych na stronie ASP.NET. Aby zdefiniować karnację, należy przede wszystkim dodać plik z rozszerzeniem.skin do odpowiedniego katalogu z motywem. Co w takim pliku może się znaleźć? Style wszystkich kontrolek serwerowych, których wygląd ma ulec zmianie. Styl dla kontrolki przypomina jej zdefiniowanie w kodzie HTML. Różnica polega na tym, że używa się jedynie właściwości odpowiedzialnych za wizualny wygląd. Na przykład karnacja dla wszystkich kontrolek LinkButton ustawiająca pogrubioną i podkreśloną czcionką koloru niebieskiego ma postać: <asp:linkbutton Font-Bold=true ForeColor="blue" Font- Underline=true runat="server" /> Style dla elementów w kodzie HTML, które nie posiadają atrybutu runat=server, można umieścić w pliku css. Definiując karnacje, wygodnie jest odwoływać się do obrazków także zdefiniowanych w ramach konkretnego motywu. Przypuśćmy, że w folderze danego motywu stworzono katalog z plikami graficznymi o nazwie obrazki z plikiem przycisk.jpg. Definiując wówczas skórkę dla kontrolki ImageButton, jako wartość ImageUrl można podać obrazki/przycisk.jpg: <asp:imagebutton ImageUrl="obrazki/przycisk.jpg" runat="server" /> Tej samej kontrolce może przypisać różne skórki z jednego motywu. Aby odróżnić kilka różnych definicji wyglądu określonych obiektów w ramach tego samego motywu, wykorzystuje się atrybut SkinID. Na stronie korzystającej z motywu, w którym zdefiniowano poniższe karnacje, każda kontrolka LinkButton będzie miała tekst w kolorze niebieskim. <asp:linkbutton Font-Bold=true ForeColor="blue" Font- Underline=true runat="server" /> <asp:linkbutton Font-Bold=true ForeColor="yellow" SkinID= YellowLink Font-Underline=true runat="server" /> <asp:linkbutton Font-Bold=true ForeColor="red" SkinID= RedLink Font-Underline=true runat="server" /> Rysunek 3. Dodawanie nowej strony z opcją wyboru strony wzorcowej Natomiast, jeśli dodamy do kontrolki SkinID= YellowLink, to kolor jej tekstu zostanie zmieniony na żółty. 24 www.sdjournal.org Software Developer s Journal Extra! 20
Rysunek 5. Widok projektowy Content Page Deklaratywne dodanie motywu Dodanie motywu do jednej strony ASP.NET odbywa się dzięki atrybutowi Theme w dyrektywie Page, np. <%@ Page Language= VB Theme= SDJ %> Powoduje to zmianę wyglądu wszystkich elementów na stronie, które zdefiniowano w motywie SDJ. Innym sposobem powiązania motywu ze stronami jest dodanie w podsekcji system.web w web.config w ramach znacznika pages atrybutu theme. <configuration> <system.web> <pages theme= SDJ /> </system.web> </configuration> Ciekawą właściwością każdej kontrolki dziedziczącej po klasie System.Web.UI.Control jest EnableTheming. Chcąc uniknąć zastosowania karnacji do pewnej konkretnej kontrolki serwerowej, należy przypisać powiazanej z nią właściwości EnableTheming wartość fałsz. Ponieważ System.Web.UI.Page również dziedziczy klasę Control, to ustawiając EnableTheming =false w dyrektywie @Page, wygląd elementów na stronie nie zostanie zmieniony wskutek globalnego zdefiniowania motywu. Sekwencja zdarzeń Programowanie aplikacji internetowych w ASP.NET to głównie definiowanie procedur obsługujących zdarzenia, dlatego istotna jest znajomość kolejności ich wywoływania. W przypadku stron wzorcowych i Content Pages cykl życia przedstawia się następująco (przyjmując skróty MP Master Page, CP Content Page): Inicjalizowanie kontrolek zdefiniowanych w MP. Inicjalizowanie kontrolek zdefiniowanych w CP. Inicjalizowanie MP Inicjalizowanie CP Ładowanie CP Ładowanie MP Ładowanie kontrolek zdefiniowanych w MP. Ładowanie kontrolek zdefiniowanych w CP. Rysunek 6. Dodawanie folderu motywu w Visual Studio.NET 2005 StylesheetTheme vs Theme Dyrektywa @Page zawiera między innymi dwie właściwości StylesheetTheme oraz Theme. Jaka różnica istnieje pomiędzy nimi? Jeśli do różnych kontrolek w obrębie danej strony z właściwością Theme dodamy lokalnie wizualne atrybuty, to zostaną one napisane przez motyw. Unika się takiej sytuacji poprzez użycie StylesheetTheme. Dodanie motywu i karnacji Podobnie jak w przypadku MasterPage motyw można dodać z poziomu code-behind przed wywołaniem zdarzenia Init, korzystając z własności Theme np.: protected void Page_PreInit(object sender, System.EventArgs e){ Page.Theme = MojMotyw ; SkinID dla konkretnej kontrolki może także zostać programistycznie dodany w Page _ Init np. id _ kontrolki. SkinID= MojaSkora ; Klasy dziedziczące po Control lub WebControl maja standardowo uaktywnione wsparcie dla motywów. Można je usunąć za pomocą właściwości [Themeable(false)]. Motywy graficzne dają ogromne możliwości, jeśli chodzi o personalizacje stron ASP.NET. W.NET Framework 2.0 istnieje pomiędzy tymi dwoma zagadnieniami bardzo silna integracja. I po co to wszystko? Środowisko programistyczne Visual Studio.NET 2005 udostępnia wachlarz nowych funkcjonalności. Widoczny jest silny nacisk na redukcję nakładu pracy programisty do minimum. Umiejętne zastosowanie np. motywów graficznych i stron wzorcowych może przysłużyć się do powstania bardziej przejrzystych wizualnie aplikacji, łatwiejszego graficznego przyozdobienia interfejsu użytkownika. Master pages znakomicie sprawdzają się we wszelkiego rodzaju portalach korporacyjnych: intra- i extranetowych, w przedsiębiorstwach o rozbudowanej strukturze organizacyjnej, wspierając kształtowanie ich marketingowego wizerunku w wirtualnym świecie (j.ang. branding). Motywy natomiast ułatwiają dostosowanie wyglądu witryny internetowej do potrzeb poszczególnych użytkowników, co bywa czynnikiem decydującym, jeśli chodzi o zapewnienie ich lojalności. Bezpośrednio przekłada się to na sukces przedsięwzięcia internetowego. Projektując serwis, należy dołożyć wszelkich starań, by osiągnąć pożądany efekt look and feel". Niewątpliwie wygląd musi pozytywnie oddziaływać na użyteczność i dostępność aplikacji. Internet jest medium o ogromnym potencjale, ma też swoje ograniczenia, których nie można zmienić; można się jedynie do nich dostosować. Spróbujcie wykorzystać opisane rozwiązania. Na pewno ułatwi to stworzenie aplikacji z charakterem. Software Developer s Journal Extra! 20 www.sdjournal.org 25