Разработка Web-приложений ASP .NET с использованием Visual Studio .NET

Использование Master Page и навигация при построении интернет-приложений

Разбить на страницы
Показывать лекцию целиком

Цель лекции: изучить принципы использования мастер-страниц при построении интернет-приложения, рассмотреть возможности применения вложенных мастер-страниц, а также организации программного взаимодействия страницы содержимого с мастер-страницей.

Создаваемые Web-страницы сегодня очень редко разрабатываются "с нуля". Обычно при создании таких страниц используются уже готовые шаблоны, либо таковые создаются в процессе разработки Web-страниц приложения. Это связано с тем, что страницы Web-приложения составляют некое единое целое, объединенное едиными требованиями к оформлению, содержанию, расположению элементов управления и т. д. Таким образом, пользователь попадает в некую среду, которая должна быть максимально удобна для удовлетворения всех потребностей пользователя.

Одним из средств решения подобных задач являются мастер-страницы (master pages). Они реализуют простую модель создания шаблонов форм с возможностью их повторного использования.

Для реализации данного механизма в ASP.NET введены такие типы страниц, как мастер-страницы (master pages) и страницы содержимого (content pages). Мастер-страница представляет собой шаблон страницы, при этом она может содержать любые элементы, допустимые для обычной страницы, а также программный код. Страница содержимого включает в себя допустимые элементы управления и с помощью их определяет содержимое, которым заполняются специальные области мастер страниц. Каждая страница содержимого ссылается на одну мастер-страницу от которой получает элементы и их расположение.

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

Для демонстрации возможностей мастер-страниц рассмотрим пример создания простой мастер-страницы и страницы содержимого. Схематично структура мастер-страницы показана на рис 6.1.

(рис 6.1) Типовая структура мастер-страницы

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

Создадим новый сайт с помощью Visual Studio. Как и всегда, по умолчанию он состоит из пустой страницы .

(рис 6.2) Окно добавления мастер-страницы к текущему Web-приложению

При этом создается новая мастер-страница с именем MainMasterPage.master. Как видно из ее исходного кода, она подобна обычной Web-странице ASP.NET Отличие заключается в том, что Web-страницы начинаются с директивы Page, а мастер-страница - с директивы Master.

<%@ Master Language="C#" AutoEventWireup="true" CodeFile=
 "MainMasterPage.master.cs" Inherits="MainMasterPage" %>

Еще одним важным отличием является то, что мастер-страница должна содержать элемент управления показана только что созданная мастер-страница во время разработки.

(рис 6.3) Редактирование мастер-страницы в режиме дизайна

Для создания страницы в соответствии со структурой, изображенной на рис 6.1, необходимо выполнить следующие действия:

  • Удалить элемент управления ContentPlaceHolder, присутствующий на мастер-странице. Это необходимо, т. к. в данном случае проще будет создать данный элемент управления заново после приведения структуры таблицы в соответствии с заданной.
  • Добавить на страницу HTML-таблицу, содержащую три строки. В первой и последней строках таблица будет содержать по одной ячейке, а во второй - две. Использование таблиц является одним из наиболее удобных способов размещения элементов внутри мастер-страниц. При таком подходе вся страница или ее часть разбивается на столбцы и строки. При этом содержимое страницы располагается и выравнивается на странице более или менее ровно. Кроме того, возможно использование дескрипторов <div> и применение позиционирования CSS, с помощью которого возможно позиционирование их содержимого либо с помощью абсолютных координат, либо располагая его вдоль одной из сторон страницы.

    Для добавления таблицы на страницу можно воспользоваться готовыми шаблонами таблиц, предоставляемых Visual Studio. Для выбора шаблона таблицы и добавления ее на страницу нужно выполнить следующую команду главного меню: Layout р Insert Table. В открывшемся окне Insert Table можно либо указать необходимое количество строк, столбцов, а также некоторые другие параметры таблицы, либо выбрать один из предлагаемых шаблонов, как показано на рис 6.4.

    (рис 6.4) Окно добавления таблицы на основе шаблона

    В данном примере выберем шаблон "Header, footer and side", позволяющий создать описанную ранее таблицу. После нажатия на кнопку OK таблица будет добавлена на текущую страницу Исходный код страницы в результате выполнения данной операции будет выглядеть следующим образом:

    <%@ Master Language="C#" AutoEventWireup="true"
     CodeFile="MainMasterPage.master.cs" Inherits="MainMasterPage" %>
    <!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>Untitled Page</title>
    </head>
    <body>
      <form id="form1" runat="server">
      <div><table border="0" cellpadding="0" cellspacing="0"
      style="width: 100%; height: 100%">
          <tr>
            <td colspan="2" style="height: 200px">
              Верхний колонититул</td>
          </tr>
          <tr>
            <td style="width: 200px">
              Меню</td>
            <td>
            </td>
          </tr>
          <tr>
            <td colspan="2" style="height: 200px">
              Нижний колонтитул</td>
          </tr>
        </table>
      </div>
      </form>
    </body>
    </html>

    Как видно, в результате данной операции была добавлена обычная HTML-таблица, для которой были установлены значения ширины и высоты некоторых ячеек. В режиме разработки дизайна страница будет выглядеть следующим образом (рис 6.5):

    (рис 6.5) Редактирование добавленной таблицы в режиме дизайна
  • Добавить элемент управления ):(рис 6.6) Добавление на страницу элемента ContentPlaceHolder
  • Установить стиль оформления ячейки, содержащей меню, в соответствии со следующими параметрами. Вертикальное выравнивание - по верхнему краю, ширина ячейки - 300 px, цвет фона ячейки - LightGrey
  • Для размещения логотипа страницы добавить ячейку в первую строку таблицы (в верхнем колонтитуле). Для этого необходимо щелкнуть правой кнопкой мыши в области верхней строки и в открывшемся контекстном меню выбрать пункт Insert р Cell to the Left. В созданную ячейку поместить изображение логотипа страницы, установить выравнивание содержимого ячейки по центру. Ввести вместо строки "верхний колонтитул" строку "Пример использования Мастер-страницы", поместить данную строку внутри тэга <h2>, создать и подключить к мастер-странице таблицу стилей (файл Stylesheet.css ), содержащую следующее определение для тега <h2>:
    h2
    {
    font-family:Tahoma;
    }
  • В результате проделанных действий мастер-страница в режиме разработки будет выглядеть следующим образом (рис 6.7):

    (рис 6.7) Результат изменения мастер-страницы

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

    В качестве страницы содержимого используем страницу Default.aspx, добавленную к проекту Web-приложения по умолчанию.

    Для того чтобы превратить обычную страницу в страницу содержимого, необходимо в качестве значения свойства MasterPageFile страницы указать имя мастер-страницы, а также добавить на страницу элемент управления <asp:Content>. Данный элемент управления отсутствует на панели элементов управления Toolbox, поэтому его можно создать либо вручную, либо одним из следующих способов:

  • Перейти в режим редактирования дизайна страницы содержимого и выполнить команду контекстного меню Create Custom Content элемента управления ). При этом активизируется содержимое данного элемента управления, в результате чего становится возможным вводить текст, а также добавлять другие элементы управления в него. Фактически при этом все вводимые данные размещаются внутри страницы (рис 6.8) Создание элемента Content с использованием контекстного меню элемента ContentPlaceHolderИсходный код страницы Default.aspx в результате проделанных операций, а также ввода текста "это начальная страница Default.aspx", будет выглядеть следующим образом:
    <%@ Page Language="C#" AutoEventWireup="true"
    	CodeFile="Default.aspx.cs" Inherits="_Default"
      MasterPageFile="~/MainMasterPage.master" %>
    <asp:Content ID="Content1" runat="server"
     ContentPlaceHolderID="ContentPlaceHolder1">
      это начальная страница Default.aspx</asp:Content>
  • При добавлении к Web-приложению новой страницы существует возможность указания мастер-страницы для нее, как показано на рис 6.9. В этом случае элемент управления (рис 6.9) Связка вновь добавляемой страницы содержимого с мастер-страницей
  • После того как страница содержимого создана, можно запустить Web-приложение. Результат представлен на рис 6.10.

    (рис 6.10) Результат работы Web-приложения на основе мастер-страниц

    Для демонстрации возможностей перехода между страницами произведем следующие изменения.

    Добавим еще одну страницу содержимого, в которую введем текст, как показано на рис 6.11. В области меню создадим две ссылки на страницы содержимого.

    (рис 6.11) Страница содержимого с размещенным на ней текстом

    Фрагмент HTML-кода, содержащего ссылки, выглядит следующим образом:

    <a href= "Default.aspx">страница1</a><br />
    <a href= "Default2.aspx">страница2</a>

    Теперь при щелчке по ссылке в области ContentPlaceHolder будет загружаться соответствующая страница.

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

    Создатели Web-приложений знают, что достаточно важное значение в этой разработке играют заголовки страниц, а также строки метадискрипторов, от которых зависит индексация страницы поисковыми роботами. Каким же образом возможно задавать заголовки страниц содержимого, ведь они фактически вкладываются в мастер-страницу? Сделать это можно двумя способами - либо задав заголовок страницы в атрибуте Title директивы Page страницы содержимого, как показано ниже,

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile=
     "Default.aspx.cs" Inherits="_Default"
     MasterPageFile="~/MasterPages/ MainMasterPage.master"
     Title="Первая страница сайта" %>

    либо обратившись к заголовку страницы из программного кода.

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

    Page masterPage = base.Master.Page;
    masterPage.Header.Title = "заголовок установлен программно";

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

    Модифицируем предыдущий пример таким образом, чтобы при обращении к странице Default.aspx с помощью гиперссылки "страница1" в верхней части мастер-страницы отображался текст "Пример обращения к мастер-странице", а при обращении к странице Default2.aspx - текст "Прямой доступ к мастер-странице". При этом рассмотрим различные способы организации доступа к элементам управления, расположенным на мастер-странице.

    В первую очередь внесем изменения в саму мастер-страницу, добавив элемент Label в верхнюю ее часть. Значение ID этого элемента установим равным lbl_BannerText. Для обращения к ресурсам мастер-страницы можно использовать либо прямое обращение к ее элементам управления, что нарушает принципы объектного подхода к разграничению прав доступа, либо создать необходимые свойства в классе мастер-страницы.

    Добавим свойство BannerText в класс мастер-страницы. Исходный текст свойства выглядит следующим образом:

    public string BannerText
    {
      get { return lbl_BannerText.Text; }
      set { lbl_BannerText.Text = value; }
    }

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

  • Добавить директиву MasterType в страницу содержимого Default.aspx, как показано ниже:
    <%@ MasterType VirtualPath="~/MasterPages/MainMasterPage.master" %>
  • В обработчике события Page_Load обратиться к свойству BannerText, установив значение отображаемой строки:
    Master.BannerText = "Пример обращения к мастер-странице";
  • Возможен и другой способ обращения к элементам управления мастер-страницы. Он очень похож на предыдущий, с той разницей, что тип объекта, возвращаемого с помощью свойства Master, приводится к типу данной мастер-страницы. Приведение типа необходимо, т. к. свойство Master возвращает объект обобщенного типа MasterPage. Естественно, данный объект не содержит тех свойств (в данном случае это BannerText ), которые мы ввели в класс конкретной мастер-страницы. В предыдущем примере приведение не требовалось, т. к. ссылка на тип была доступна через директиву MasterType. Исходный код обращения к свойству BannerText мастер-страницы MainMasterPage будет выглядеть следующим образом:

    MainMasterPage master=(MainMasterPage) Master;
    master.BannerText= "Пример обращения к мастер-странице";

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

    Еще одной возможностью для доступа к элементам мастер-страницы является прямой доступ к ним. Для демонстрации возможностей данного способа создадим пример, в котором страница содержимого Default2.aspx будет изменять текст баннера мастер-страницы на следующий: "Прямой доступ к мастер-странице".

    Для этого создадим в обработчике события Page_Load страницы Default2.aspx следующий код:

    Label lbl = Master.FindControl("lbl_BannerText") as Label;
     if (lbl != null)
    lbl.Text = "Прямой доступ к мастер-странице";

    Как видно из данного примера, сначала происходит поиск элемента управления lbl_BannerText, и, в случае успеха, устанавливается значение свойства Text.

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

    Для изменения текущей мастер-страницы программным способом необходимо задать имя файла новой мастер-страницы в свойстве Page.MasterPageFile. Делать это можно в событии Page.Prelnit страницы содержимого. При этом нужно учесть следующее: мастер-страницы, на которые будут переключаться страницы содержимого, должны быть "совместимы" друг с другом. Т. е. они должны содержать одинаковые элементы управления (одинакового типа, с одинаковыми значениями ID), в противном случае произойдет ошибка при попытке обращения к какому-либо из них. Кроме того, если страница содержимого, для которой предполагается динамическое изменение мастер-страницы, должна программно обращаться к элементам мастер-страницы, это обращение необходимо осуществлять напрямую, без применения строго типизированного подхода на основе создания свойств мастер-страницы, как было показано ранее. При этом использовать директиву <%@ MasterType %> нежелательно.

    В качестве примера добавим к предыдущему примеру еще одну мастер-страницу .

    (рис 6.12) Вторая мастер-страница, добавленная к Web-приложению

    Добавим в обе мастер-страницы кнопку "Изменить мастер-страницу", ID которой равно btn_ChangeMasterPage. Обработчик события этой кнопки для обеих мастер-страниц будет одинаковым.

    protected void btn_ChangeMasterPage_Click(object sender,
    EventArgs e)
    {
      if (Request.Browser.Cookies)
      {
        if (Request.Cookies["masterpage"] != null)
        {
          if (Request.Cookies["masterpage"].Value == "1")
            Response.Cookies["masterpage"].Value = "2";
          else
            Response.Cookies["masterpage"].Value = "1";
        }
        else
        {
          HttpCookie mpage = new HttpCookie("masterpage");
          mpage.Expires = DateTime.Now.AddDays(1);
          mpage.Value = "2";
          Response.Cookies.Add(mpage);
        }
      }
      Response.Redirect(Request.RawUrl);
    }

    Как видно, здесь применяется механизм Cookies для запоминания текущей мастер-страницы, а также задания той из них, которая будет использоваться в качестве текущей. Сам cookie назван masterpage. При значении masterpage=1 активной будет мастер-страница MainMasterPage, при masterpage=2 - OtherMasterPage. Команда Response.Redirect (Request.RawUrl) ; необходима для того, чтобы перегрузить текущую страницу, изменив, таким образом, ее внешний вид за счет подключения другой мастер-страницы. Само подключение другой мастер-страницы происходит в обработчике события Page.PreInit каждой страницы содержимого. В данном примере для обеих страниц содержимого, хранящихся в файлах Default.aspx и Default2.aspx, создан одинаковый обработчик события Page.PreInit, исходный код которого приведен ниже.

    protected void Page_PreInit(object sender, EventArgs e)
      {
        if (Request.Browser.Cookies)
          if (Request.Cookies["masterpage"] != null)
            if (Request.Cookies["masterpage"].Value == "1")
            {
    Page.MasterPageFile = "~//MasterPages// MainMasterPage.master";
            }
            else
            {
    Page.MasterPageFile = "~//MasterPages// OtherMasterPage.master";
            }
      }

    В зависимости от значения cookie masterpage устанавливается текущая мастер-страница.

    В результате при нажатии на кнопку Изменить мастер-страницу оформление текущей страницы изменится, а содержимое останется прежним (рис 6.13).

    (рис 6.13) Пример динамического изменения мастер-страницы

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

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

    Мастер-страница верхнего уровня ( RootMasterPage.master ):

    <%@ Master Language="C#" AutoEventWireup="true"
     CodeFile="RootMasterPage.master.cs" Inherits="RootMasterPage" %>
    
    <!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>Untitled Page</title>
    </head>
    <body>
      <form id="form1" runat="server">
      <div>
        <table border="0" cellpadding="0" cellspacing="0"
        style="width: 100%; height: 100%">
          <tr>
            <td style="height: 7px">
              <h1>Общий заголовок для всех страниц
               Web-приложения</h1>
            </td>
          </tr>
          <tr>
            <td>
              <asp:ContentPlaceHolder ID="ContentPlaceHolder1"
               runat="server">
              </asp:ContentPlaceHolder>
            </td>
          </tr>
        </table>
      </div>
      </form>
    </body>
    </html>

    Мастер-страница второго уровня ( Node1MasterPage.master ):

    <%@ Master Language="C#" AutoEventWireup="true"
    CodeFile="Node1MasterPage.master.cs" Inherits="Node1MasterPage"
    MasterPageFile="~/MasterPages/RootMasterPage.master" %>
      <asp:Content ID="Content1"
       ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
        <table border="0" cellpadding="0" cellspacing="0"
         style="width: 100%; height: 100%">
          <tr>
            <td style="height: 200px;background-color: lightgrey;">
              Здесь располагается меню
            </td>
            <td>
              <asp:ContentPlaceHolder ID="CPH2" runat="server">
              </asp:ContentPlaceHolder>
            </td>
          </tr>
        </table>
      </asp:Content>

    Страница содержимого ( Default3.aspx ):

    <%@ Page Language="C#" MasterPageFile="~/MasterPages/
     Node1MasterPage.master" AutoEventWireup="true"
     CodeFile="Default3.aspx.cs" Inherits="Default3" Title=
     "Untitled Page" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="CPH2"
     Runat="Server">
    <h3>содержимое вложенной мастер-страницы</h3>
    </asp:Content>

    В результате выполнения приложения окно браузера будет выглядеть следующим образом:

    (рис 6.14) Результат выполнения приложения, содержащего вложенные мастер-страницы

    Краткие итоги

    В настоящее время Web-приложения редко создаются "с нуля", обычно для их создания используются готовые шаблоны. Эти шаблоны необходимы для оформления множества различных страниц, составляющих интернет-приложение, в едином стиле. В ASP.NET реализован эффективный механизм создания и использования таких шаблонов - мастер-страницы. Обычно мастер-страница содержит фиксированные элементы, одинаковые для всех страниц, и заполнитель содержимого для остальной части страницы.

    В момент обращения пользователя к странице Web-приложения среда ASP.NET осуществляет проверку принадлежности данной страницы к какой-либо мастер-странице. В случае положительного результата страница содержимого получает от мастер-страницы фиксированные элементы и предоставляет дополнительное содержимое. Сформированная таким образом страница передается клиенту для отображения в браузере. Таким образом, мастер-страница не может быть отображена в окне браузера клиента, т. к. она содержит элементы, используемые для формирования страницы содержимого и отправки ее клиенту.

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

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

    Страницы:

    Цель лекции: изучить принципы использования мастер-страниц при построении интернет-приложения, рассмотреть возможности применения вложенных мастер-страниц, а также организации программного взаимодействия страницы содержимого с мастер-страницей.

    Создаваемые Web-страницы сегодня очень редко разрабатываются "с нуля". Обычно при создании таких страниц используются уже готовые шаблоны, либо таковые создаются в процессе разработки Web-страниц приложения. Это связано с тем, что страницы Web-приложения составляют некое единое целое, объединенное едиными требованиями к оформлению, содержанию, расположению элементов управления и т. д. Таким образом, пользователь попадает в некую среду, которая должна быть максимально удобна для удовлетворения всех потребностей пользователя.

    Одним из средств решения подобных задач являются мастер-страницы (master pages). Они реализуют простую модель создания шаблонов форм с возможностью их повторного использования.

    Для реализации данного механизма в ASP.NET введены такие типы страниц, как мастер-страницы (master pages) и страницы содержимого (content pages). Мастер-страница представляет собой шаблон страницы, при этом она может содержать любые элементы, допустимые для обычной страницы, а также программный код. Страница содержимого включает в себя допустимые элементы управления и с помощью их определяет содержимое, которым заполняются специальные области мастер страниц. Каждая страница содержимого ссылается на одну мастер-страницу от которой получает элементы и их расположение.

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

    Для демонстрации возможностей мастер-страниц рассмотрим пример создания простой мастер-страницы и страницы содержимого. Схематично структура мастер-страницы показана на рис 6.1.

    (рис 6.1) Типовая структура мастер-страницы

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

    Создадим новый сайт с помощью Visual Studio. Как и всегда, по умолчанию он состоит из пустой страницы .

    (рис 6.2) Окно добавления мастер-страницы к текущему Web-приложению

    При этом создается новая мастер-страница с именем MainMasterPage.master. Как видно из ее исходного кода, она подобна обычной Web-странице ASP.NET Отличие заключается в том, что Web-страницы начинаются с директивы Page, а мастер-страница - с директивы Master.

    <%@ Master Language="C#" AutoEventWireup="true" CodeFile=
     "MainMasterPage.master.cs" Inherits="MainMasterPage" %>

    Еще одним важным отличием является то, что мастер-страница должна содержать элемент управления показана только что созданная мастер-страница во время разработки.

    (рис 6.3) Редактирование мастер-страницы в режиме дизайна

    Для создания страницы в соответствии со структурой, изображенной на рис 6.1, необходимо выполнить следующие действия:

  • Удалить элемент управления ContentPlaceHolder, присутствующий на мастер-странице. Это необходимо, т. к. в данном случае проще будет создать данный элемент управления заново после приведения структуры таблицы в соответствии с заданной.
  • Добавить на страницу HTML-таблицу, содержащую три строки. В первой и последней строках таблица будет содержать по одной ячейке, а во второй - две. Использование таблиц является одним из наиболее удобных способов размещения элементов внутри мастер-страниц. При таком подходе вся страница или ее часть разбивается на столбцы и строки. При этом содержимое страницы располагается и выравнивается на странице более или менее ровно. Кроме того, возможно использование дескрипторов <div> и применение позиционирования CSS, с помощью которого возможно позиционирование их содержимого либо с помощью абсолютных координат, либо располагая его вдоль одной из сторон страницы.

    Для добавления таблицы на страницу можно воспользоваться готовыми шаблонами таблиц, предоставляемых Visual Studio. Для выбора шаблона таблицы и добавления ее на страницу нужно выполнить следующую команду главного меню: Layout р Insert Table. В открывшемся окне Insert Table можно либо указать необходимое количество строк, столбцов, а также некоторые другие параметры таблицы, либо выбрать один из предлагаемых шаблонов, как показано на рис 6.4.

    (рис 6.4) Окно добавления таблицы на основе шаблона

    В данном примере выберем шаблон "Header, footer and side", позволяющий создать описанную ранее таблицу. После нажатия на кнопку OK таблица будет добавлена на текущую страницу Исходный код страницы в результате выполнения данной операции будет выглядеть следующим образом:

    <%@ Master Language="C#" AutoEventWireup="true"
     CodeFile="MainMasterPage.master.cs" Inherits="MainMasterPage" %>
    <!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>Untitled Page</title>
    </head>
    <body>
      <form id="form1" runat="server">
      <div><table border="0" cellpadding="0" cellspacing="0"
      style="width: 100%; height: 100%">
          <tr>
            <td colspan="2" style="height: 200px">
              Верхний колонититул</td>
          </tr>
          <tr>
            <td style="width: 200px">
              Меню</td>
            <td>
            </td>
          </tr>
          <tr>
            <td colspan="2" style="height: 200px">
              Нижний колонтитул</td>
          </tr>
        </table>
      </div>
      </form>
    </body>
    </html>

    Как видно, в результате данной операции была добавлена обычная HTML-таблица, для которой были установлены значения ширины и высоты некоторых ячеек. В режиме разработки дизайна страница будет выглядеть следующим образом (рис 6.5):

    (рис 6.5) Редактирование добавленной таблицы в режиме дизайна
  • Добавить элемент управления ):(рис 6.6) Добавление на страницу элемента ContentPlaceHolder
  • Установить стиль оформления ячейки, содержащей меню, в соответствии со следующими параметрами. Вертикальное выравнивание - по верхнему краю, ширина ячейки - 300 px, цвет фона ячейки - LightGrey
  • Для размещения логотипа страницы добавить ячейку в первую строку таблицы (в верхнем колонтитуле). Для этого необходимо щелкнуть правой кнопкой мыши в области верхней строки и в открывшемся контекстном меню выбрать пункт Insert р Cell to the Left. В созданную ячейку поместить изображение логотипа страницы, установить выравнивание содержимого ячейки по центру. Ввести вместо строки "верхний колонтитул" строку "Пример использования Мастер-страницы", поместить данную строку внутри тэга <h2>, создать и подключить к мастер-странице таблицу стилей (файл Stylesheet.css ), содержащую следующее определение для тега <h2>:
    h2
    {
    font-family:Tahoma;
    }
  • В результате проделанных действий мастер-страница в режиме разработки будет выглядеть следующим образом (рис 6.7):

    (рис 6.7) Результат изменения мастер-страницы

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

    В качестве страницы содержимого используем страницу Default.aspx, добавленную к проекту Web-приложения по умолчанию.

    Для того чтобы превратить обычную страницу в страницу содержимого, необходимо в качестве значения свойства MasterPageFile страницы указать имя мастер-страницы, а также добавить на страницу элемент управления <asp:Content>. Данный элемент управления отсутствует на панели элементов управления Toolbox, поэтому его можно создать либо вручную, либо одним из следующих способов:

  • Перейти в режим редактирования дизайна страницы содержимого и выполнить команду контекстного меню Create Custom Content элемента управления ). При этом активизируется содержимое данного элемента управления, в результате чего становится возможным вводить текст, а также добавлять другие элементы управления в него. Фактически при этом все вводимые данные размещаются внутри страницы (рис 6.8) Создание элемента Content с использованием контекстного меню элемента ContentPlaceHolderИсходный код страницы Default.aspx в результате проделанных операций, а также ввода текста "это начальная страница Default.aspx", будет выглядеть следующим образом:
    <%@ Page Language="C#" AutoEventWireup="true"
    	CodeFile="Default.aspx.cs" Inherits="_Default"
      MasterPageFile="~/MainMasterPage.master" %>
    <asp:Content ID="Content1" runat="server"
     ContentPlaceHolderID="ContentPlaceHolder1">
      это начальная страница Default.aspx</asp:Content>
  • При добавлении к Web-приложению новой страницы существует возможность указания мастер-страницы для нее, как показано на рис 6.9. В этом случае элемент управления (рис 6.9) Связка вновь добавляемой страницы содержимого с мастер-страницей
  • После того как страница содержимого создана, можно запустить Web-приложение. Результат представлен на рис 6.10.

    (рис 6.10) Результат работы Web-приложения на основе мастер-страниц

    Для демонстрации возможностей перехода между страницами произведем следующие изменения.

    Добавим еще одну страницу содержимого, в которую введем текст, как показано на рис 6.11. В области меню создадим две ссылки на страницы содержимого.

    (рис 6.11) Страница содержимого с размещенным на ней текстом

    Фрагмент HTML-кода, содержащего ссылки, выглядит следующим образом:

    <a href= "Default.aspx">страница1</a><br />
    <a href= "Default2.aspx">страница2</a>

    Теперь при щелчке по ссылке в области ContentPlaceHolder будет загружаться соответствующая страница.

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

    Создатели Web-приложений знают, что достаточно важное значение в этой разработке играют заголовки страниц, а также строки метадискрипторов, от которых зависит индексация страницы поисковыми роботами. Каким же образом возможно задавать заголовки страниц содержимого, ведь они фактически вкладываются в мастер-страницу? Сделать это можно двумя способами - либо задав заголовок страницы в атрибуте Title директивы Page страницы содержимого, как показано ниже,

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile=
     "Default.aspx.cs" Inherits="_Default"
     MasterPageFile="~/MasterPages/ MainMasterPage.master"
     Title="Первая страница сайта" %>

    либо обратившись к заголовку страницы из программного кода.

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

    Page masterPage = base.Master.Page;
    masterPage.Header.Title = "заголовок установлен программно";

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

    Модифицируем предыдущий пример таким образом, чтобы при обращении к странице Default.aspx с помощью гиперссылки "страница1" в верхней части мастер-страницы отображался текст "Пример обращения к мастер-странице", а при обращении к странице Default2.aspx - текст "Прямой доступ к мастер-странице". При этом рассмотрим различные способы организации доступа к элементам управления, расположенным на мастер-странице.

    В первую очередь внесем изменения в саму мастер-страницу, добавив элемент Label в верхнюю ее часть. Значение ID этого элемента установим равным lbl_BannerText. Для обращения к ресурсам мастер-страницы можно использовать либо прямое обращение к ее элементам управления, что нарушает принципы объектного подхода к разграничению прав доступа, либо создать необходимые свойства в классе мастер-страницы.

    Добавим свойство BannerText в класс мастер-страницы. Исходный текст свойства выглядит следующим образом:

    public string BannerText
    {
      get { return lbl_BannerText.Text; }
      set { lbl_BannerText.Text = value; }
    }

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

  • Добавить директиву MasterType в страницу содержимого Default.aspx, как показано ниже:
    <%@ MasterType VirtualPath="~/MasterPages/MainMasterPage.master" %>
  • В обработчике события Page_Load обратиться к свойству BannerText, установив значение отображаемой строки:
    Master.BannerText = "Пример обращения к мастер-странице";
  • Возможен и другой способ обращения к элементам управления мастер-страницы. Он очень похож на предыдущий, с той разницей, что тип объекта, возвращаемого с помощью свойства Master, приводится к типу данной мастер-страницы. Приведение типа необходимо, т. к. свойство Master возвращает объект обобщенного типа MasterPage. Естественно, данный объект не содержит тех свойств (в данном случае это BannerText ), которые мы ввели в класс конкретной мастер-страницы. В предыдущем примере приведение не требовалось, т. к. ссылка на тип была доступна через директиву MasterType. Исходный код обращения к свойству BannerText мастер-страницы MainMasterPage будет выглядеть следующим образом:

    MainMasterPage master=(MainMasterPage) Master;
    master.BannerText= "Пример обращения к мастер-странице";

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

    Еще одной возможностью для доступа к элементам мастер-страницы является прямой доступ к ним. Для демонстрации возможностей данного способа создадим пример, в котором страница содержимого Default2.aspx будет изменять текст баннера мастер-страницы на следующий: "Прямой доступ к мастер-странице".

    Для этого создадим в обработчике события Page_Load страницы Default2.aspx следующий код:

    Label lbl = Master.FindControl("lbl_BannerText") as Label;
     if (lbl != null)
    lbl.Text = "Прямой доступ к мастер-странице";

    Как видно из данного примера, сначала происходит поиск элемента управления lbl_BannerText, и, в случае успеха, устанавливается значение свойства Text.

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

    Для изменения текущей мастер-страницы программным способом необходимо задать имя файла новой мастер-страницы в свойстве Page.MasterPageFile. Делать это можно в событии Page.Prelnit страницы содержимого. При этом нужно учесть следующее: мастер-страницы, на которые будут переключаться страницы содержимого, должны быть "совместимы" друг с другом. Т. е. они должны содержать одинаковые элементы управления (одинакового типа, с одинаковыми значениями ID), в противном случае произойдет ошибка при попытке обращения к какому-либо из них. Кроме того, если страница содержимого, для которой предполагается динамическое изменение мастер-страницы, должна программно обращаться к элементам мастер-страницы, это обращение необходимо осуществлять напрямую, без применения строго типизированного подхода на основе создания свойств мастер-страницы, как было показано ранее. При этом использовать директиву <%@ MasterType %> нежелательно.

    В качестве примера добавим к предыдущему примеру еще одну мастер-страницу .

    (рис 6.12) Вторая мастер-страница, добавленная к Web-приложению

    Добавим в обе мастер-страницы кнопку "Изменить мастер-страницу", ID которой равно btn_ChangeMasterPage. Обработчик события этой кнопки для обеих мастер-страниц будет одинаковым.

    protected void btn_ChangeMasterPage_Click(object sender,
    EventArgs e)
    {
      if (Request.Browser.Cookies)
      {
        if (Request.Cookies["masterpage"] != null)
        {
          if (Request.Cookies["masterpage"].Value == "1")
            Response.Cookies["masterpage"].Value = "2";
          else
            Response.Cookies["masterpage"].Value = "1";
        }
        else
        {
          HttpCookie mpage = new HttpCookie("masterpage");
          mpage.Expires = DateTime.Now.AddDays(1);
          mpage.Value = "2";
          Response.Cookies.Add(mpage);
        }
      }
      Response.Redirect(Request.RawUrl);
    }

    Как видно, здесь применяется механизм Cookies для запоминания текущей мастер-страницы, а также задания той из них, которая будет использоваться в качестве текущей. Сам cookie назван masterpage. При значении masterpage=1 активной будет мастер-страница MainMasterPage, при masterpage=2 - OtherMasterPage. Команда Response.Redirect (Request.RawUrl) ; необходима для того, чтобы перегрузить текущую страницу, изменив, таким образом, ее внешний вид за счет подключения другой мастер-страницы. Само подключение другой мастер-страницы происходит в обработчике события Page.PreInit каждой страницы содержимого. В данном примере для обеих страниц содержимого, хранящихся в файлах Default.aspx и Default2.aspx, создан одинаковый обработчик события Page.PreInit, исходный код которого приведен ниже.

    protected void Page_PreInit(object sender, EventArgs e)
      {
        if (Request.Browser.Cookies)
          if (Request.Cookies["masterpage"] != null)
            if (Request.Cookies["masterpage"].Value == "1")
            {
    Page.MasterPageFile = "~//MasterPages// MainMasterPage.master";
            }
            else
            {
    Page.MasterPageFile = "~//MasterPages// OtherMasterPage.master";
            }
      }

    В зависимости от значения cookie masterpage устанавливается текущая мастер-страница.

    В результате при нажатии на кнопку Изменить мастер-страницу оформление текущей страницы изменится, а содержимое останется прежним (рис 6.13).

    (рис 6.13) Пример динамического изменения мастер-страницы

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

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

    Мастер-страница верхнего уровня ( RootMasterPage.master ):

    <%@ Master Language="C#" AutoEventWireup="true"
     CodeFile="RootMasterPage.master.cs" Inherits="RootMasterPage" %>
    
    <!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>Untitled Page</title>
    </head>
    <body>
      <form id="form1" runat="server">
      <div>
        <table border="0" cellpadding="0" cellspacing="0"
        style="width: 100%; height: 100%">
          <tr>
            <td style="height: 7px">
              <h1>Общий заголовок для всех страниц
               Web-приложения</h1>
            </td>
          </tr>
          <tr>
            <td>
              <asp:ContentPlaceHolder ID="ContentPlaceHolder1"
               runat="server">
              </asp:ContentPlaceHolder>
            </td>
          </tr>
        </table>
      </div>
      </form>
    </body>
    </html>

    Мастер-страница второго уровня ( Node1MasterPage.master ):

    <%@ Master Language="C#" AutoEventWireup="true"
    CodeFile="Node1MasterPage.master.cs" Inherits="Node1MasterPage"
    MasterPageFile="~/MasterPages/RootMasterPage.master" %>
      <asp:Content ID="Content1"
       ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
        <table border="0" cellpadding="0" cellspacing="0"
         style="width: 100%; height: 100%">
          <tr>
            <td style="height: 200px;background-color: lightgrey;">
              Здесь располагается меню
            </td>
            <td>
              <asp:ContentPlaceHolder ID="CPH2" runat="server">
              </asp:ContentPlaceHolder>
            </td>
          </tr>
        </table>
      </asp:Content>

    Страница содержимого ( Default3.aspx ):

    <%@ Page Language="C#" MasterPageFile="~/MasterPages/
     Node1MasterPage.master" AutoEventWireup="true"
     CodeFile="Default3.aspx.cs" Inherits="Default3" Title=
     "Untitled Page" %>
    <asp:Content ID="Content1" ContentPlaceHolderID="CPH2"
     Runat="Server">
    <h3>содержимое вложенной мастер-страницы</h3>
    </asp:Content>

    В результате выполнения приложения окно браузера будет выглядеть следующим образом:

    (рис 6.14) Результат выполнения приложения, содержащего вложенные мастер-страницы

    Краткие итоги

    В настоящее время Web-приложения редко создаются "с нуля", обычно для их создания используются готовые шаблоны. Эти шаблоны необходимы для оформления множества различных страниц, составляющих интернет-приложение, в едином стиле. В ASP.NET реализован эффективный механизм создания и использования таких шаблонов - мастер-страницы. Обычно мастер-страница содержит фиксированные элементы, одинаковые для всех страниц, и заполнитель содержимого для остальной части страницы.

    В момент обращения пользователя к странице Web-приложения среда ASP.NET осуществляет проверку принадлежности данной страницы к какой-либо мастер-странице. В случае положительного результата страница содержимого получает от мастер-страницы фиксированные элементы и предоставляет дополнительное содержимое. Сформированная таким образом страница передается клиенту для отображения в браузере. Таким образом, мастер-страница не может быть отображена в окне браузера клиента, т. к. она содержит элементы, используемые для формирования страницы содержимого и отправки ее клиенту.

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

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

    Вернуться к учебному плану