ASP.Net. Лекция 12. Шаблоны дизайна страниц ASP.NET (исходники)

Асмик Гаряка

Лекция 11

Шаблоны дизайна - это визуальное наследование страниц, впервые появившееся в ASP.NET 2.0. Вы можете создавать основу для любого количества страниц приложения. Шаблоны позволяют легче создавать и поддерживать приложения. Visual Studio 2005 включает поддержку создания и редактирования шаблонов страниц. Эта лекция рассматривает использование шаблонов страниц в приложении и начинается с объяснения их преимуществ.

Примечание: терминология в этой области не устоялась. В некоторых книгах используют выражение «эталонные страницы». Можно применять термин «главная страница», хотя его можно спутать с Default.aspx.

Зачем нужны шаблоны дизайна страниц?

Для простого пользователя отличие одного сайта от другого - в разнообразном дизайне страниц. Большинство веб-сайтов сегодня имеют узнаваемый дизайн, который достигается использованием одних и тех же элементов в тех же самых местах в разных страницах сайта. Поэтому дизайн страниц является едва ли менее важным, чем общая функциональность.

Например, взгляните на главную страницу сайта газеты «Комсомольская правда». Каждый день там появляются разные статьи, но оформление их остается единым. Это логотип газеты, верхние, правые, левые навигационные панели, рейтинг статей справа, формы для поиска, подписки и входа в почту. Внизу страницы находится юридическая информация.

Некоторые разработчики копируют и вставляют повторяющиеся элементы во всех страницах. Это неэффективно, если нужно изменить одну деталь в этих общих элементах, изменения придется вводить во всех страницах. Можно помещать повторяющиеся куски кода во включаемые файлы с помощью команды HTML include. Но так трудно увидеть окончательный вид страницы в среде разработки. В ASP.NET 1.1 стало возможным создавать пользовательские элементы управления. Можно создать такой элемент с нужным содержанием и помещать его на все страницы. Развитием этой идеи стало создание шаблонов страниц. Это тоже пользовательский элемент управления, только он находится не в странице, а вне ее.

Основы Master Pages

С помощью шаблонов страниц вы определяете некоторое общее содержание и помещаете ее в страницу с расширением .master. Естественно, таких страниц в приложении может быть несколько. Этой шаблон могут использовать любое количество дочерних страниц, которые как и обычные страницы, имеют расширение aspx.

Начиная с этой лекции, будем разбирать проект, который Visual Studio 2005 создает по шаблону Personal Web Site Starter Kit. В нем показаны шаблоны страниц, темы и персонализация и навигация. Элементы управления навигации сосредоточены на странице шаблона Default.master. И это естественное решение, так как навигация нужна везде.

В страницу шаблона также включают общие заголовки и нижние колонтитулы.

Это единственный тип страниц, где возможно разместить специальные элементы управления ContentPlaceHolder. Они определяют места, в которое дочерние страницы данного мастера могут помещать свое собственное содержание. Когда ASP.NET получает запрос отобразить дочернюю страницу, она сливает ее код с кодом главной страницы, в результате генерируется HTML, в котором не видно никаких «швов».

Когда дочерняя страница редактируется в среде разработки, на вкладке Design видна полная страница вместе с элементами из шаблона, но они показаны серым цветом. Их редактировать нельзя. Можно редактировать то, что находится в элементах Content.

В диалоге Add New Item выберите тип страницы Master Page. Как и обычные страницы, их можно создавать с отделенным кодом или кодом, встроенным в страницу. Это никак не влияет на модель разделения кода дочерних+ страниц. Кроме того, главная и дочерняя страницы могут разрабатываться на разных языках.

Чтобы получить четкое разделение страницы на логические части, используют таблицы. Построим таблицу с 3 строками, где в верхней строке находится заголовок всех страниц, во второй произвольное содержание, она состоит из двух ячеек, в каждой из которых по одному ContentPlaceHolder. В нижнем ряду находится правовая информация. Таблица создается очень просто из меню Layout-Insert Table. Создайте таблицу 2 на 3. После этого объедините ячейки верхней и нижней строк, а в среднюю вставьте ContentPlaceHolder. Создайте содержание заголовка и подвала. Должна получиться подобная страница:

  <%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %> 
  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  <html xmlns="http://www.w3.org/1999/xhtml" > 
  <head runat="server"> 
      <title>Привет!</title> 
  </head> 
  <body> 
      <form id="form1" runat="server"> 
      <div> 
          <table> 
              <tr bgcolor="#6699cc"> 
                  <td colspan="2" style="vertical-align: middle; 
      color: white; 
      text-align: center;">Школа программирования ASP.NET 2.0 
                  </td> 
              </tr> 
              <tr> 
                  <td style="width: 100px" valign="top"> 
          <asp:contentplaceholder id="ContentPlaceHolder1" runat="server"> 
          </asp:contentplaceholder> 
                  </td> 
                  <td style="width: 100px" valign="top"> 
                      <asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server"> 
                      </asp:ContentPlaceHolder> 
                  </td> 
              </tr> 
              <tr> 
                  <td colspan="2"> 
                      <span style="font-size: 8pt">Copyright © 2006 - Школа ASP.NET 2.0</span></td> 
              </tr> 
          </table> 
      </div> 
      </form> 
  </body> 
  </html> 
  

Первое отличие этой страницы от обычной в том, что она начинается с директивы Master, а не Page. Класс мастер-страницы определен в файле MasterPage.master.cs.

  public partial class MasterPage : System.Web.UI.MasterPage 
  { 
      protected void Page_Load(object sender, EventArgs e) 
      { 
      } 
  } 
  

Класс шаблона - наследник System.Web.UI.MasterPage, который в свою очередь наследует от System.Web.UI.UserControl.

В ней могут находиться любые элементы управления и HTML-код. В ней могут обрабатываться и события страницы. 2 элемента ContentPlaceHolder обозначают места, куда вставляется содержание страницы-наследницы.

Теперь нужно создать страницу содержания. Она создается как обычно, только отмечается флажок с надписью Select Master Page. Появляется диалог, в котором необходимо выбрать шаблон страницы.

   <%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="MainSchool.aspx.cs" Inherits="MainSchool" Title="Untitled Page" %>
  

Атрибут MasterPage директивы Page определяет шаблон дизайна, или эталонную страницу данной страницы.

Возможно настроить приложение так, чтобы все страницы наследовали одну страницу шаблона дизайна. В конфигурационном файле в секцию web.config

нужно вставить элемент:

          <pages masterPageFile="~/ MasterPage.master " />
  

Но и в этом случае назначение главной страницы в директиве Page имеет приоритет над назначением на уровне приложения. Установка web.config действует на тех страницах, в которых masterPageFile не указан, но определены элементы управления Content. Эта установка не действует на обычные aspx-страницы.

Шаблон можно назначить не всем страницам, а выборочно, например, расположенным в определенной папке приложения.

    <location path="Lections"> 
      <system.web> 
        <pages masterPageFile="~/Lections.master" /> 
      </system.web>  
  

Элемент location вставляется в главный узел configuration. Здесь указано, что все страницы из папки Lections используют шаблонную страницу Lections.master.

На странице-наследнице шаблона могут быть только элементы типа Content, каждый из который соответствует одному элементу ContentPlaceHolder шаблона. Нельзя вставлять содержание вне этих элементов, иначе ASP.NET не сможет объединить главную страницу со страницей содержания. Идентификатор ContentPlaceHolder должен совпадать с атрибутом ContentPlaceHolderID соответствующего элемента Content.

  <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> 
  </asp:Content> 
  <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder2" Runat="Server"> 
  </asp:Content> 
  

Программа создала дочернюю страницу с 2 элементами управления Content. Если переключиться на вкладку Design, эти два элемента Content показаны в виде пустых прямоугольников, расположенных рядом друг с другом, так как в шаблоне они находятся в двух соседних ячейках таблицы. Директива Page отличается от обычной, кроме атрибута MasterPageFile, наличием атрибута Title. Так как теги <head>, <title>, <body> наследуются из файла шаблона, это единственная возможность переопределить заголовок браузера. Заменим значение атрибута

  Title="Главная"
  

Если посмотреть на результирующую страницу в браузере, увидим, что в заголовок браузера отразил изменение. В HTML-коде страницы записано

  <title>
              Главная
  </title>
  

На самой странице отображается только содержание, заданное в странице шаблона.

Шаблон можно в любой момент отредактировать, и изменения отразятся на всех производных страницах. Например, добавим картинку перед текстом заголовка.

  <img src=" images/ASPdotNET_logo.jpg" />
  

(Ее можно найти в установке .NET "Microsoft.NET\Framework\v2.0.xxx\ASP.NETWebAdminFiles\Images)

Дочерняя страница в браузере теперь выглядит так:

Содержание страницы должно быть строго внутри элементов Content. В один из них можно поместить, например, картинку, а во второй текст.

  <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> 
    <asp:Image ID="Image1" runat="server"  ImageUrl="Images/photo_home_01.jpg" /> 
  </asp:Content> 
  <asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder2" Runat="Server"> 
    Вы решили изучить ASP.NET?<br /> 
Преимущество технологии ASP.NET перед остальными в высокой степени абстракции, построенной над стандартным HTML кодом: 
использование объектно-ориентированной парадигмы, поддержку нескольких языков программирования, 
наличие универсального основания, содержащего тысячи уже готовых для использования в проектах решений - Microsoft .NET Framework.
    <br /> 
    <asp:HyperLink ID="HyperLink1" runat="server"  NavigateUrl="Voting.aspx">Дальше</asp:HyperLink> 
  </asp:Content> 
  

Есть еще один способ поменять заголовок браузера программно. У страницы, имеющей шаблон, есть свойство Master. Конечно, оно есть у всех страниц, но у обычных страниц оно равно Null. Через него можно обращаться ко всем свойствам главной страницы. Это свойство только для чтения.

  public MasterPage Master { get; }
  public partial class MainSchool : System.Web.UI.Page 
  { 
      protected void Page_LoadComplete(object sender, EventArgs e) 
      { 
        Master.Page.Title = "Школа веб-программирования"; 
      } 
  

Содержание по умолчанию

В главной странице может быть определено содержание, которое будет отображаться по умолчанию. Оно помещается в элементах ContentPlaceHolder и наследуется всеми дочерними страницами. Если дочерняя страница не переопределит содержание по умолчанию, оно будет использоваться при ее отображении. Создадим элемент управления SiteMapPath, которым поместим в ContentPlaceHolder1.

          <asp:contentplaceholder id="ContentPlaceHolder1" runat="server"> 
            <asp:SiteMapPath ID="SiteMapPath1" runat="server"> 
            </asp:SiteMapPath> 
          </asp:contentplaceholder>  
  

На странице MainSchool.aspx он отображаться не будет, так как в ней определены оба элемента Content. Однако если в следующей странице определен только один из элементов Content:

  <%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Voting.aspx.cs"  
  Inherits="Voting" MasterPageFile="~/MasterPage.master" %> 
  <asp:Content ContentPlaceHolderID="ContentPlaceHolder2" runat="server"> 
  Какой язык программирования Вы предпочитаете?<br /> 
      asp:RadioButtonList ID="rblVoting" runat="server" DataSourceID="SqlDataSource1" 
          DataTextField="variant" DataValueField="id"> 
      </asp:RadioButtonList> <br /> 
      <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:PollsConnectionString %>" 
          SelectCommand="SELECT [id], [variant] FROM [poll] ORDER BY [variant] "></asp:SqlDataSource> 
      <br /> 
       <asp:Button ID="Button1" runat="server" Text="Выбрать" /><br /> 
  </asp:Content> 
  

Если посмотреть ее в браузере, увидим, что в ее левой части «хлебные крошки» отображаются.

Программное назначение мастер страницы

В странице содержания можно переназначить ее главную страницу программно. Для этого нужно присвоить нужное значение свойству Page.MasterPageFile. Шаблон поменяется независимо от того, какой шаблон был назначен в директиве @Page. Но если попробуете проделать это в функциях Page_Load или Page_Init, получите ошибку времени выполнения.

Это свойство можно изменить только во время обработки события Page_PreInit. Событие Page_PreInit - самая ранняя фаза жизненного цикла страницы, к которой можно получить доступ. Во время события Init главная и дочерняя страница уже сливаются в одну, поэтому уже поздно менять шаблон. По этой причине событие Page_PreInit единственное, в обработчике которого можно работать с главной страницей отдельно от страницы содержания.

  protected void Page_PreInit(object sender, EventArgs e)
  {
  Page.MasterPageFile = "~/MyMasterPage.master";
  }
  

Для того, чтобы из страницы содержания обратитьс к элементам управления главной страницы, можно воспользоваться функцией FindControl. Непосредственно обратиться к ним нельзя, так как это защищенные члены.

    Label mpLabel = (Label) Master.FindControl("masterPageLabel"); 
    if(mpLabel != null) 
    { 
       //Set content page title to master page control 
       Title.Text = mpLabel.Text 
    }
  

Страницы шаблона могут иметь методы и свойства. Чтобы можно было обращаться к ним, нужно использовать директиву @MasterType. При этом становится доступен класс страницы шаблона дизайна через строго типизированную ссылку. Атрибут TypeName задает имя типа, а VirtualPath путь относительно корневого каталога веб-приложения к файлу шаблона.

  <%@ page language="C#" masterpagefile="~/Site3.master" %> 
  <%@ mastertype virtualpath="~/Site3.master" %> 
  Свойства могут быть определены в классе главной страницы. 
      public String FooterText { 
          get {  
              return Footer.Text;  
          } 
          set {  
              Footer.Text = value;  
          } 
      } 
  

Таким образом страница разрешает доступ извне к свойствам своих элементов.

Страница содержания меняет это свойство, а элемент управления AdRotator находит с помощью FindControl:

    void Page_Load() 
    { 
      Master.FooterText = "This is a custom footer"; 
      AdRotator ad = (AdRotator)Master.FindControl("MyAdRotator"); 
      if (ad != null) 
      { 
        ad.BorderColor = System.Drawing.Color.Purple; 
        ad.BorderWidth = 10; 
      } 
    } 
  

Вложенные мастер-страницы

Шаблоны дизайна могут наследовать другие шаблоны. Например, сайт состоит из нескольких разделов. Все страницы сайта имеют общие элементы, и все страницы раздела имеют другие общие элементы. Сайт цветочного магазина состоит из разделов многолетних и однолетних цветов. Для них созданы шаблоны, которые наследуют общий шаблон сайта.

  <%@ master language="C#" masterpagefile="~/Site4.master"%> 
  <asp:content contentplaceholderid="SectionContents" runat="server"> 
      <h3>Perrenials</h3> 
      <asp:contentplaceholder id="FlowerText" runat="server"/> 
      <br /><br /> 
      <asp:contentplaceholder id="FlowerPicture" runat="server"/> 
  </asp:content> 
  

Страница, описывающая нарциссы, находится в разделе многолетних цветов и наследует шаблон SectionPerrenials.

  <%@ page language="C#" masterpagefile="~/SectionPerrenials.master" %> 
  <asp:content id="FlowerText" ContentPlaceHolderId="FlowerText" runat="server"> 
      Daffodils bloom early in spring and welcome the growing season. 
  </asp:content> 
  <asp:content id="FlowerPicture" ContentPlaceHolderId="FlowerPicture" runat="server"> 
      <asp:image id="image1" runat=server imageurl="~/images/daffodil.jpg"/> 
  </asp:content> 
  

Последовательность событий

Когда составная страница формируется на сервере, происходят события и страницы шаблона, и страницы содержания. Порядок этих событий полезно знать, если мы хотим программировать их обработчики.

Инициализация вложенных элементов управления главной страницы.

Инициализация вложенных элементов управления страницы содержания.

Инициализация самой главной страницы.

Инициализация страницы содержания.

Загрузка(Page_Load) страницы содержания.

Загрузка(Page_Load) главной страницы

Событие Page_LoadComplete страницы содержания

Загрузка дочерних элементов управления управления главной страницы.

Загрузка дочерних элементов управления управления страницы содержания.

Событие LoadComplete было введено для того, чтобы можно было обратиться из страницы содержания к элементам главной страницы, созданным в ее Page_Load. Это нельзя сделать в обработчике Page_Load страницы содержания, так как она загружается до главной страницы.

Страницы шаблонов для конкретных платформ

Во многих случаях приложения разрабатываются для просмотра на разных видах контейнеров. Это могут быть различные браузеры или программы просмотра веб-сайтов на карманных компьютерах и мобильных телефонах.

Поэтому ASP.NET 2.0 позволяет в атрибуте MasterPageFile директивы Page определить разные страницы шаблона для конкретных контейнеров.

  <%@ Page Language="VB" MasterPageFile="~/Main.master"
  Mozilla:MasterPageFile="~/MainMozilla.master"
  Opera:MasterPageFile="~/MainOpera.master" %>
  

Заключение

При создании приложений, в которых все страницы включают общие заголовки, подвалы и систему навигации жизнь могут облегчить шаблоны дизайна. Их легко применять и их можно изменять в любой момент, обновляя при этом все приложение.


Страница сайта http://test.interface.ru
Оригинал находится по адресу http://test.interface.ru/home.asp?artId=6279