V minulém díle jsme si popsali úplné základy tvorby stránky v ASP.NET 2.0. Víme již, že můžeme využívat serverové komponenty, které mají svoje události, na něž můžeme reagovat, máme i základní povědomí o tom, jak to funguje. Můžeme se tedy pustit dále, dnes si ukážeme, jak využít tzv. MasterPage.
Většina webových aplikací má jednotné uživatelské rozhraní - nahoře je logo, na boku menu, dole copyright a napravo třeba novinky a odkazy na nejnovější obsah. A někam doprostřed mezi to všechno dynamicky dosazujeme obsah, který si uživatel vyžádal. Dříve se to dalo řešit pomocí rámců, které okno prohlížeče rozdělily na několik autonomních stránek, jež se mohly ovlivňovat navzájem (kliknutím na odkaz v jednom rámci se otevřela stránka v rámci jiném). Pokud to mělo být bez rámců, dalo se využít SSI (Server Side Includes), anebo jakoukoliv skriptovací technologii na straně serveru (např. PHP).
Často se celý layout rozdělil na tři části - header (hlavička), footer (patička) a dynamická část. A právě do dynamické části se přidaly dvě includes (vsuvky) - jedna úplně nahoru vložila do stránky header a druhá úplně dolů vložila footer. Výsledkem bylo, že adresa URL ukazovala na požadovanou stránku, která si sama před sebe dala hlavičku a za sebe patičku. Není to rozhodně jediné používané řešení a určitě není ideální, ale zvláště mezi začátečníky našlo velkou oblibu.
ASP.NET (nejen) přistupuje k problému jinak - pomocí MasterPages. MasterPage je speciální stránka, která obvykle začíná značkami <!DOCTYPE... a <html> a končí značkou </html>. Najdete v ní celý layout se vším všudy, až na dynamickou část. Ta je nahrazena komponentou ContentPlaceHolder a právě do ní se dynamický obsah dosadí.
MasterPage je ale sama o sobě k ničemu - v prohlížeči na ni neodkazujeme (má příponu .master a ne .aspx). Musíme tedy kromě ní vytvořit normální stránku, do které dáme dynamický obsah (třeba jej vypíšeme z databáze atd.). Celý dynamický obsah musí být uvnitř komponenty Content, které navíc musíme nastavit hodnotu vlastnosti ContentPlaceHolderId na ID ContentPlaceHolderu v MasterPage, do kterého dosazujeme. Navíc v direktivě Page této stránky musíme specifikovat vlastnost MasterPageFile, která ukazuje na příslušný MasterPage. Možná si řeknete, že je toho nastavování nějak moc, ale většinu toho za nás stejně udělá Visual Studio 2005 či Visual Web Developer.
První seznámení s MasterPage
Spusťte si vývojové prostředí a pokud máte projekt z minula, klidně jej otevřete kliknutím na jeho název na úvodní stránce. Můžete ale klidně vytvořit nový, je to úplně jedno.
V projektu byste měli nyní mít soubor Default.aspx. V podokně Solution Explorer na něj klikněte pravým tlačítkem a zvolte možnost Delete, čímž tento soubor smažete. Dále pravým tlačítkem klikněte na první položku (název projektu) a zvolte položku Add New Item.... Zobrazí se dialog pro výběr typu nové položky.
Vyberte typ MasterPage, zkontrolujte, že není zaškrtnuto pole Place code in separate file, které by zapříčinilo, že kód bude umístěn do druhého souboru. Vyberte si svůj oblíbený programovací jazyk (pro tentokrát je to ale jedno, kód dnes psát nebudeme), nakonec potvrďte tlačítkem Add a je hotovo.
Přepněte se do režimu Source a prohlédněte si kód, který stránka obsahuje.
<%@ Master Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder>
</div>
</form>
</body>
</html>
První řádek je direktiva Master, která definuje jazyk stránky (záleží, který jste si v dialogu zvolili). Následuje nám jistě důverně známá deklarace !DOCTYPE, která říká, že dokument má být XHTML 1.0 Transitional. Nic neobvyklého.
První zvláštnost, která by nás mohla zaskočit, je sekce <script runat="server"></script>. To je divné, značka script by měla být přece v sekci head, případně body. Atribut runat by nám ale mohl něco prozradit - asi to bude jen pro server. A je to pravda. V dialogu jsme úmyslně nezaškrtli Place code in separate file, čímž jsme zajistili, že na rozdíl od minula se kód na pozadí (code-behind) bude nyní vkládat do stejného souboru jako deklarativní popis vzhledu stránky (HTML a komponenty). Konkrétně se code-behind vloží právě do této sekce, čímž je tedy záhada zbloudilé sekce script odtajněna a můžeme pokračovat dále.
Následuje totiž standardní struktura HTML stránky - html, head, title atd., všichni to dobře známe. Uvnitř formuláře je komponenta ContentPlaceHolder, o které jsem již psal na začátku článku. Do ní se dosadí obsah vkládané stránky. Abychom nasimulovali reálnou aplikaci, vytvoříme alespoň primitivní layout. Upravte tedy kód stránky MasterPage.master, aby vypadal takto:
<%@ Master Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled page</title>
<style>
#header {
background-color: #c0ffa0;
width: 100%;
}
#header h1 {
margin: 0.5em;
}
#footer {
font-size: 80%;
text-align: center;
}
</style>
</head>
<body>
<form id="form1" runat="server">
<div id="header">
<h1>První web s MasterPage</h1>
</div>
<div>
<asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
</asp:contentplaceholder>
</div>
<p id="footer">© 2007 VbNet.cz</p>
</form>
</body>
</html>
Layout je to opravdu primitivní (pokud se to dá nazvat vůbec layoutem), omlouvám se také za tu hnusnou zelenou, nejsem designér a nemám estetické cítění. Ještě musím podotknout, že MasterPage může obsahovat více komponent ContentPlaceHolder, takže můžeme mít dynamických částí libovolný počet.
Stránka s obsahem
Abychom nemuseli obsahovou stránku vytvářet ručně (musí v ní být komponenta Content a je to trocha nastavování), může to opět vývojové prostředí udělat za nás. V okně Solution Explorer tedy klikněte pravým tlačítkem na naši MasterPage.master a vyberte volbu Add Content Page. Visual Studio vytvoří obsahovou stránku "na míru" pro vybranou MasterPage.
Nově vytvořená stránka nyní nebude obsahovat žádné značky html, head apod., jediné, co v ní bude, je komponenta Content. Její vlastnost ContentPlaceHolderID je nastavena na ID odpovídající komponenty v MasterPage a do ní se také dosadí.
Vnitřně to funguje o něco složitěji, MasterPage je vlastně serverová komponenta a je uchována v kolekci Controls ve stránce s obsahem. To je pro nás ale v tuto chvíli nepodstatné.
Pokud se podíváme na kód obsahové stránky, vypadá zhruba takto:
<%@ Page Language="VB" MasterPageFile="~/MasterPage.master" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
</asp:Content>
Veškerý obsah, který chceme zobrazit, musíme umístit dovnitř elementu Content. V direktivě Page vidíme dvě podstatné vlastnosti - MasterPageFile (určuje cestu k MasterPage) a Title. Do Title napište název stránky - např. "První ASP.NET stránka". Hodnota této vlastnosti se nastaví do hlavičky stránky.
Možná vás trochu zarazil zápis cesty ve vlastnosti MasterPageFile. Tento zápis se používá v ASP.NET velmi často, znak ~ (tilda) označuje kořenový adresář naší webové aplikace. Hodí se to v případě, pokud potřebujete odkázat na nějaký soubor a nevíte, kde přesně se v rámci aplikace nacházíte (často se to stává, když píšete vlastní komponenty - nikdy předem nevíte, kde leží stránka, která komponentu využívá). Často ani nevíte, jestli aplikace leží přímo v kořenové URL adrese serveru (www.něco.cz), nebo v nějakém virtuálním adresáři (www.něco.cz/aplikace), nemůžete tedy adresy začínat jen lomítkem (třeba /Default.aspx). Proto se používá vlnovka, která se o tyto případy postará. Funguje prakticky u všech serverových komponent, nikoliv pochopitelně u HTML značek odkazů, obrázků atd., které nemají runat="server".
Vraťme se ale k samotné stránce, vepište do ní nějaký odstavec a nějaké HTML, uložte a stiskněte klávesovou zkratku Ctrl+F5. Stránka se objeví v prohlížeči a mezi záhlavím a zápatím v MasterPage se objeví námi vytvořená obsahová stránka. Komponenty a jejich události by fungovaly samozřejmě pořád, nic se prakticky nemění.
Pár odkazů
Abyste viděli, jak se odkazuje na dynamické stránky, přidejte si druhou Content Page a pojmenujte ji Druha.aspx. Napište do ní opět nějaký text, nastavte jí titulek v direktivě Page a do stránky Default.aspx vložte tento odkaz:
<a href="Druha.aspx">Druhá stránka</a>
Pokud v prohlížeči stránku obnovíte klávesou F5, objeví se v ní přidaný odkaz. Pokud na něj kliknete, ukáže se druhá stránka.
Potíž s adresami by nastala, kdybychom chtěli dát do MasterPage menu, které by odkazovalo na stránky v různých složkách. Zde bychom museli použít komponentu HyperLink, což je vlastně jakési "zaobalení" klasického <a href=.... Umí totiž adresy s vlnovkou.
Pokud třeba budu mít MasterPage, které bude odkazovat na stránky Default.aspx a Admin/Default.aspx, obě včleněné do této MasterPage, musím použít asp:HyperLink. Pokud bych v MasterPage použil obyčejné odkazy na Default.aspx a Admin/Default.aspx, nefungovaly by již ze stránky Admin/Default.aspx, protože první by odkazoval na tu samou adresu a druhý na adresu Admin/Admin/Default.aspx, která ale samozřejmě neexistuje. Pokud použijeme adresy ~/Default.aspx a ~/Admin/Default.aspx, nemusíme se ničeho bát. Normální odkaz je ale nezvládne, musíme tedy použít komponentu. Menu by vypadalo takto:
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl="~/Default.aspx">Home</asp:HyperLink>
<asp:HyperLink ID="HyperLink2" runat="server" NavigateUrl="~/Admin/Default.aspx">Administrace</asp:HyperLink>
Vlastnost NavigateUrl obsahuje adresu, která se nejprve převede (vlnovka se nahradí relativní cestou z aktuálního umístění do kořene aplikace), a pak teprve vypíše do stránky jako odkaz.
Zbývá ještě jednou připomenout, že nikdy neodkazujeme na samotný MasterPage, ale vždy na content pages, tedy na stránky s obsahem. A ještě by bylo vhodné připomenout, že ASP.NET podporuje i složitější včleňování - i MasterPage můžete včlenit stejným způsobem do jiného MasterPage.
Podotýkám, že ASP.NET má vestavěné sofistikovanější nástroje a funkce pro tvorbu menu a mapy webu, má i některé předpřipravené komponenty, celý tento model menu je lokalizovatelný a automaticky umí skrývat uživateli ty položky, ke kterým nemá přístup. O tom ale až někdy příště, je to na nás zatím příliš složité.
Pro dnešek je to vše, v příštím díle si předvedeme základy práce s databází. Doufám, že se vám tutoriál líbí, jakékoliv připomínky či náměty pište do diskuse.