Jedním z hesel MVC frameworku je: „neopakuj se“. Naše aplikace to ale ani zdaleka nedodržuje, měli bychom s tím něco udělat! Proto si dnes uvedeme tzv. „partial pages“ a ve druhé části článku i „master pages“, které dost možná znáte i z klasických WebForms.
Dobrá, říct, že naše aplikace ani zdaleka nedodržuje heslo „neopakuj se“, není tak úplně pravda. Vždyť jsme například oddělili validační logiku, takže je nezávislá na zbytku aplikace, v minulém dílu jsme vytvořili třídu DinnerFormViewModel, kterou používá jak metoda Edit, tak i metoda Create. Možná jste si ale u Edit a Create view šablon všimli, že si jsou velmi podobné, a nejen to, až na nadpis a titulek jsou absolutně identické! Máme tedy zbytečný duplicitní kód ve dvou souborech. Nevýhody jsou stejné jako u každého duplicitního kódu – pokud chceme udělat nějakou změnu ve formuláři, musíme ji provést hned dvakrát a může se snadno stát, že na úpravu druhé kopie zapomeneme. S vyřešením tohoto problému nám pomůžou právě partial šablony („částečné“ šablony).
Použití partial view šablon
V ASP.NET MVC můžeme nadefinovat „částečnou“ view šablonu, která definuje vzhled nějaké části stránky, samozřejmě tuto šablonu můžeme použít v tolika view, kolik se nám jen zachce.
Abychom přidali partial view, klikneme pravým tlačítkem na adresář Dinners ve složceViews a zvolíme možnost „Add > View“. Zobrazí se nám už dobře známý dialog, ale tentokrát ho nastavíme trochu jinak. Nový view pojmenujeme DinnerForm a zaškrtneme možnost „Create a partial view (.ascx)“.
Do nového souboru pak už stačí zkopírovat společný obsah pro obě původní view šablony, tedy to, co je v následující ukázce:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<NerdDinner.Controllers.DinnerFormViewModel>" %>
<%=Html.ValidationSummary("Opravte prosím všechny chyby a zkuste to znovu.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<p>
<label for="Title">Název:</label>
<%= Html.TextBox("Title", Model.Dinner.Title) %>
<%= Html.ValidationMessage("Title", "*") %>
</p>
<p>
<label for="EventDate">Datum:</label>
<%=Html.TextBox("EventDate", Model.Dinner.EventDate) %>
<%=Html.ValidationMessage("EventDate", "*") %>
</p>
<p>
<label for="Description">Popis:</label>
<%=Html.TextArea("Description", Model.Dinner.Description) %>
<%=Html.ValidationMessage("Description", "*") %>
</p>
<p>
<label for="Address">Adresa:</label>
<%=Html.TextBox("Address", Model.Dinner.Address) %>
<%=Html.ValidationMessage("Address", "*") %>
</p>
<p>
<label for="Country">Země:</label>
<%=Html.DropDownList("Country", Model.Countries) %>
<%=Html.ValidationMessage("Country", "*") %>
</p>
<p>
<label for="ContactPhone">Telefon:</label>
<%=Html.TextBox("ContactPhone", Model.Dinner.ContactPhone) %>
<%=Html.ValidationMessage("ContactPhone", "*") %>
</p>
<p>
<label for="Latitude">Zem. šířka:</label>
<%=Html.TextBox("Latitude", Model.Dinner.Latitude) %>
<%=Html.ValidationMessage("Latitude", "*") %>
</p>
<p>
<label for="Longitude">Zem. délka:</label>
<%=Html.TextBox("Longitude", Model.Dinner.Longitude) %>
<%=Html.ValidationMessage("Longitude", "*") %>
</p>
<p>
<input type="submit" value="Uložit"/>
</p>
</fieldset>
<% } %>
Když teď chceme z Create a Edit šablon odkázat na použití nové partial šablony, tak nám jen stačí zavolat pomocnou metodu Html.RenderPartial:
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerFormViewModel>" %>
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Vytvořit večeři
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Vytvořit večeři</h2>
<% Html.RenderPartial("DinnerForm"); %>
</asp:Content>
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerFormViewModel>" %>
<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
Upravit: <%=Html.Encode(Model.Dinner.Title)%>
</asp:Content>
<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">
<h2>Upravit večeři</h2>
<% Html.RenderPartial("DinnerForm"); %>
</asp:Content>
Použití partial šablon pro zpřehlednění kódu
Nejčastější způsob, proč použijeme partial šablony, bude použití opakujícího se kusu kódu. Často mají ale i druhé využití, i když se kód použije jen jednou. Když třeba máme složitou stránku, tak někdy může být vhodné vyčlenit nějaký složitější ovládací prvek do samostatného souboru, aby se nepletl (za chvíli uvidíme tento způsob využití u master pages).
Master pages
Kdo někdy pracoval s klasickými WebForms, tak master pages dost možná zná. Slouží k nadefinování společného vzhledu pro různé stránky aplikace, proto mají všechny stránky v naší aplikaci stejný modro-bílý design. Výchozí master page v ASP.NET MVC projektu se jmenuje Site.Master a najdeme ji v adresáři „/Views/Shared“ společně se souborem LogOnUserControl.ascx, který obsahuje definici tlačítka pro přihlášení uživatele a využívá konceptu partial šablon.
Základní master page v MVC projektu vypadá následovně. Všimněte si dvou ContentPlaceHolderů, do kterých jsme doteď dosazovali obsah všech našich view šablon.
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="page">
<div id="header">
<div id="title">
<h1>My MVC Application</h1>
</div>
<div id="logindisplay">
<% Html.RenderPartial("LogOnUserControl"); %>
</div>
<div id="menucontainer">
<ul id="menu">
<li><%= Html.ActionLink("Home", "Index", "Home")%></li>
<li><%= Html.ActionLink("About", "About", "Home")%></li>
</ul>
</div>
</div>
<div id="main">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
<div id="footer">
</div>
</div>
</div>
</body>
</html>
To, jakou master page chceme pro content page (to je stránka nebo view, kterou do master page vkládáme) použít, určuje direktiva Page ve view šabloně:
<%@ Page Inherits="System.Web.Mvc.ViewPage<NerdDinner.Controllers.DinnerViewModel>" MasterPageFile="~/Views/Shared/Site.Master" %>
Teď je načase master page trochu upravit, abychom neměli název aplikace „My MVC Application“ a tak podobně:
<%@ Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title>
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="page">
<div id="header">
<div id="title">
<h1>NerdDinner</h1>
</div>
<div id="logindisplay">
<% Html.RenderPartial("LogOnUserControl"); %>
</div>
<div id="menucontainer">
<ul id="menu">
<li><%= Html.ActionLink("Seznam večeří", "Index", "Dinners")%></li>
<li><%= Html.ActionLink("Vytvořit večeři", "Create", "Dinners")%></li>
<li><%= Html.ActionLink("O webu", "About", "Home")%></li>
</ul>
</div>
</div>
<div id="main">
<asp:ContentPlaceHolder ID="MainContent" runat="server" />
</div>
</div>
</body>
</html>
Dnes jsme si ukázali, jak partial views a master pages můžou zpřehlednit a zjednodušit kód aplikace. Příště přidáme podporu stránkování pro seznam večeří. Zatím doporučuji, abyste si přidali několik večeří do databáze, abyste si také mohli stránkování vyzkoušet.