Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 31:

Стилевое оформление страниц

Упражнение 12. Переключение тем по выбору пользователя

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

Все, что нужно сделать, это предусмотреть на странице интерфейс выбора темы, а в коде страницы динамически присвоить свойству Page.Theme или Page.StyleSheetTheme выбранное пользователем значение. При этом важно понимать, что тема настраивается перед инициализацией страницы, поэтому соответствующий код нужно поместить в обработчик Page_PreInit(). Если это сделать позже, в обработчиках других событий, то попытка присвоить новое значение свойству Page.Theme или Page.StyleSheetTheme вызовет ошибку компиляции.

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

  1. Прочитать выбор пользователя, когда это станет возможным после полной загрузки страницы
  2. Принудительно перезапустить страницу на сервере, чтобы в обработчике Page_PreInit() назначить новую тему

При перезапуске страницы она должна быть переадресована на саму себя. Такую операцию можно выполнить либо методом Response.Redirect(), либо методом Server.Transfer(). Первый метод реализует полный цикл с отправкой на броузер и автоматическим возвращением на сервер. Он тратит лишнее время на пересылку. Второй метод перезапускает страницу сразу на сервере без цикла через клиента. Но есть одна существенная особенность: оба метода сбрасывают состояние вида всех элементов управления и запускают страницу как в при первом запросе. Поскольку выбирать не из чего, то мы применим второй метод Server.Transfer().

Рассмотрим все это на примере. Прежде всего, нужно создать несколько тем, чтобы было из чего пользователю выбирать.

  • В панели Sulution Explorer вызовите контекстное меню для папки MyTheme и выполните команду Copy
  • В панели Sulution Explorer вызовите контекстное меню для папки App_Themes, где должны храниться все темы приложения, и выполните на ней команду Paste два раза, чтобы создать еще две темы
  • Присвойте копиям имена, например, MyTheme1 и MyTheme2

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

Учитывая, что протокол HTTP не поддерживает сохранение состояний и что страница существует только на время обработки обратной отсылки, выбранную пользователем тему нужно где-то сохранять. Это могут быть cookie -наборы ( куки -файлы) на компьютере клиента, которые мы туда запишем без его ведома, если он забыл выключить их поддержку. Это могут быть скрытые поля состояния вида (VIEWSTATE), которые мы будем пересылать туда-сюда. Это могут быть глобальные объекты уровня сеанса или приложения, которые существуют на сервере, пока не закончится сеанс с пользователем или не закроется приложение. Выберем объект уровня сеанса Session.

  • Через панель Solution Explorer скопируйте в корневой виртуальный каталог нашего сайта файл TestTheme.aspx и назовите его TestSwitchThemes.aspx
  • Определите новую страницу TestSwitchThemes.aspx стартовой
  • Откройте файл TestSwitchThemes.aspx на редактирование и добавьте в верхнюю часть страницы из вкладки Standard элемент списока DropDownList для выбора темы
  • Переименуйте ID списка в lstSwitchThemes
  • Через панель Properties в режиме Events создайте для списка заготовку обработчика события SelectedIndexChanged, которое поступит на сервер с обратной отсылкой, если пользователь изменит выбор в списке
  • Добавьте на страницу перед списком серверный элемент Label с именем lblFirstLoad

Интерфейсная часть страницы TestSwitchThemes.aspx примет следующий вид


Код интерфейсной части страницы TestSwitchThemes.aspx следующий

<%@ Page AutoEventWireup="true" CodeFile="TestSwitchThemes.aspx.cs" 
    Inherits="TestSwitchThemes" Language="C#" %>
    
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Label ID="lblFirstLoad" runat="server" Text="Label"></asp:Label>
        <br />
        <asp:DropDownList ID="lstSwitchThemes" runat="server"
                          OnSelectedIndexChanged="lstSwitchThemes_SelectedIndexChanged">
        </asp:DropDownList>
        <br />
        <asp:BulletedList ID="BulletedList1" runat="server">
            <asp:ListItem>Туризм</asp:ListItem>
            <asp:ListItem>Спорт</asp:ListItem>
            <asp:ListItem>Музыка</asp:ListItem>
            <asp:ListItem Value="Танцы"></asp:ListItem>
        </asp:BulletedList>
        <asp:Label ID="Label1" runat="server" Text="Текстовая метка"></asp:Label>
        <asp:CheckBox ID="CheckBox1" runat="server" Text="Флажок" /><br />
        <br />
        <asp:Button ID="Button1" runat="server" Text="Отправить" /></div>
    </form>
</body>
</html>
Листинг 31.21. Код интерфейсной части страницы TestSwitchThemes.aspx
  • Откройте на редактирование файл кода TestSwitchThemes.aspx.cs и заполните его так
using System;
    
public partial class TestSwitchThemes : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            lblFirstLoad.Text = "Первая загрузка страницы";
      
            // Заполняем список именами каталогов тем
            System.IO.DirectoryInfo themeDir =
                new System.IO.DirectoryInfo(Server.MapPath("App_Themes"));
            lstSwitchThemes.DataTextField = "Name";
            lstSwitchThemes.DataSource = themeDir.GetDirectories();
            lstSwitchThemes.DataBind();
        }
        else
            lblFirstLoad.Text = "Повторная загрузка страницы";
    }
      
    protected void Page_PreInit(object sender, EventArgs e)
    {
        if (Session["Theme"] != null)
        {
            // Был ранее сохраненный выбор, включить его
            Page.Theme = (string)Session["Theme"];
      
            // Восстанавливаем новое состояние списка
            lstSwitchThemes.SelectedIndex = (int)Session["index"];
            // Восстанавливаем текущее состояние "Флажка" 
            CheckBox1.Checked = (bool)Session["Флажок"];
        }
    }
    
    protected void lstSwitchThemes_SelectedIndexChanged(object sender, EventArgs e)
    {
        // Запоминаем новый выбор пользователя
        Session["Theme"] = lstSwitchThemes.SelectedValue;
        // Запоминаем новое состояние списка
        Session["index"] = lstSwitchThemes.SelectedIndex;
        // Сохраняем текущее состояние "Флажка"
        Session["Флажок"] = CheckBox1.Checked;
      
        // Первый вариант:
        // Обновляем страницу с полным циклом,
        // чтобы новая тема вступила в действие
        //Response.Redirect(Request.Url.ToString());
      
        // Второй вариант:
        // Обновляем страницу без полного цикла,
        // чтобы новая тема вступила в действие
        Server.Transfer(Request.FilePath);
    }
}
Листинг 31.22. Код выбора темы файла TestSwitchThemes.aspx.cs

Сделаем некоторые пояснения по кодовой части страницы:

  1. В коде используется подключение только одного пространства имен System, потому что:
    • объекты пользовательского интерфейса определены в интерфейсной части страницы и не требуют явного указания пространства имен
    • класс System.IO. DirectoryInfo прописан с полным путем и компилятор его увидит
    • объекты Session, Server, Response, Request являются общедоступными свойствами класса System.Web.UI.Page, который наследуется нашим классом TestSwitchThemes и явно приобретает все эти свойства
  2. Оставлено объявление пространства имен System только потому, что в коде имеются ключевые слова string, int, bool, используемые при явном приведении типов. Но и здесь можно было бы использовать полные имена библиотечных типов System. string, System. int, System. bool
  3. При принудительной перезагрузке страницы полностью сбрасывается состояние ее элементов управления в начальное, поэтому мы вынуждены его сохранять и восстанавливать в объекте сеанса
  4. Язык C# допускает использование в идентификаторах символов кириллицы при условии соблюдения общепринятых правил: должны состоять из букв цифр и знаков подчеркивания, не должны начинаться с цифры, и т.д.
  5. При внутренней обработке кода страницы можно (в разумных пределах) использовать весь арсенал библиотеки .NET Framework, а не только специализированные Web-средства

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

  • Вызовите на редактирование файл App_Themes/MyTheme1/ThemeCSS.css и поменяйте в селекторе body определение стиля фона background, чтобы фон страницы стал зеленым
body
        {
          background:green;
          font-family:Arial, Helvetica, sans-serif;
        }
  • Вызовите на редактирование файл App_Themes/MyTheme2/ThemeCSS.css и поменяйте в селекторе body определение стиля фона background, чтобы фон страницы стал красным
body
        {
          background:red;
          font-family:Arial, Helvetica, sans-serif;
        }
  • Исполните страницу и убедитесь в том, что пользователь может сам выбирать варианты стилевого оформления страниц подключением соответствующих тем

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

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

Мастер-страницы

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

Шаблон размечает именованные области визуализации на исполнимой странице, в которых будут размещены либо прикрепленные группы элементов страницы, либо содержимое именованной области самого шаблона. Группы элементов управления страницы, закрепленные за именованными областями шаблона, называются содержимым (content). Страница, к которой подключен шаблон, должна содержать замещающие группы, каждая из которых может ссылаться только на одну именованную область шаблона. Если для какой-то именованной области шаблона прикрепленной группы нет, то на странице появится содержимое именованной области самого шаблона.

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

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

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

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

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

Упражнение 13. Простая мастер-страница

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

  • Добавьте к проекту командой Website/Add New Item шаблон с именем FirstMasterPage.master с разделяемым кодом

Вот какой дескрипторный код создал мастер

<%@ Master Language="C#" AutoEventWireup="true" 
    CodeFile="FirstMasterPage.master.cs" 
    Inherits="FirstMasterPage" %>
  
<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>
Листинг 31.25. Дескрипторный код шаблона FirstMasterPage.master

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

  1. Шаблоны нельзя выполнить напрямую, они могут только поддерживать ссылающиеся на них исполнимые страницы
  2. Файлы шаблонов имеют расширение .master, а файлы кода поддержки для них на языке C# - .master.cs
  3. В декларации интерфейсного представления шаблона вместо директивы @Page используется директива @Master
  4. Класс кода поддержки шаблона наследует базовый класс System.Web.UI.MasterPage, вместо базового класса System.Web.UI.Page для обычной исполнимой страницы
  5. Элемент управления ContentPlaceHolder используется для резервирования именованных контекстных областей только в шаблонах. Если раскрыть вкладку Standard контекстно-зависимой панели Toolbox при редактировании обычной страницы, то мы этого элемента просто не увидим, поскольку оболочка его скрывает до случая редактирования шаблона
  6. Элементы ContentPlaceHolder ( держатель места для содержимого ) шаблонной страницы можно размещать в ячейках таблицы. При выполнении эти ячейки заполнятся присоединенным содержимым, а остальные ячейки можно занять заполнителем, который будет виден и доступен на любой странице, использующей этот шаблон
  7. При загрузке страницы во время выполнения вначале создается объект мастер-страницы, а потом сама страница с содержимым
  8. Во время выполнения именованные области мастер-страницы сжимаются до минимального размера фактического содержимого
  • Удалите из кода мастер-страницы созданный автоматически дескриптор ContentPlaceHolder и через контекстное меню редактора выполните команду Add Content Page (добавить контекстную страницу)


Оболочка сгенерирует такую заготовку файла Default.aspx

<%@ Page Language="C#" MasterPageFile="~/FirstMasterPage.master" 
    AutoEventWireup="true" CodeFile="Default.aspx.cs" 
    Inherits="_Default" Title="Untitled Page" %>
<%-- Add content controls here --%>
Листинг 31.26. Заготовка контекстной страницы в файле Default.aspx

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

Обратите внимание, как можно вставлять комментарии <%--...--%> в дескрипторный код файлов ASP.NET

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

  • Создайте в панели Solution Explorer через контекстное меню для корня Web-дерева проекта командой New Folder каталог MasterPages
  • Переместите мышью в папку MasterPages шаблон FirstMasterPage.master

Откорректируем дескрипторный код контекстной страницы, для этого:

  • В панели Solution Explorer дайте файлу Default.aspx новое имя FirstMasterPage.aspx
  • Откорректируйте дескрипторный код страницы FirstMasterPage.aspx, указав новое местоположение шаблона, переименовав класс поддержки страницы и назначив заголовок окна броузера
<%@ Page Language="C#" 
    MasterPageFile="~/MasterPages/FirstMasterPage.master" 
    AutoEventWireup="true" CodeFile="FirstMasterPage.aspx.cs" 
    Inherits="FirstMasterPage" Title="Тестовая страница содержимого" %>
<%-- Add content controls here --%>
Листинг 31.27. Скорректированный код страницы FirstMasterPage.aspx
  • Откройте файл FirstMasterPage.aspx.cs командой View Code контекстного меню страницы и измените имя _Default класса страницы на FirstMasterPage
  • Назначьте страницу FirstMasterPage.aspx стартовой и исполните ее, чтобы убедиться в отсутствии ошибок

Появилась пустая страница с фоном, определенным темой по умолчанию MyTheme, включенной нами ранее в конфигурационный файл web.config

<configuration>
  <system.web>
    <pages theme="MyTheme" />
  </system.web>
</configuration>
Листинг 31.28. Тема по умолчанию в конфигурационном файле Web.Config

Никакого содержимого страница пока не имеет.

  • Добавьте в файл FirstMasterPage.aspx произвольный текст, например
<%@ Page Language="C#" 
    MasterPageFile="~/MasterPages/FirstMasterPage.master" 
    AutoEventWireup="true" CodeFile="FirstMasterPage.aspx.cs" 
    Inherits="FirstMasterPage" Title="Тестовая страница содержимого" %>
    
<%-- Add content controls here --%>
<h1>Привет студентам из "страницы содержимого1"!</h1>
Листинг 31.29. Добавили строку в контекстную страницу FirstMasterPage.aspx

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

<asp:Content></asp:Content>

  • Поместите строку текста в контейнер <asp:Content> и исполните страницу
<%@ Page Language="C#" 
    MasterPageFile="~/MasterPages/FirstMasterPage.master" 
    AutoEventWireup="true" CodeFile="FirstMasterPage.aspx.cs" 
    Inherits="FirstMasterPage" Title="Тестовая страница содержимого" %>
    
<%-- Add content controls here --%>
<asp:Content>
    <h1>Привет студентам из "страницы содержимого1"!</h1>    
</asp:Content>
Листинг 31.30. Поместили строку в контейнер на странице FirstMasterPage.aspx

Вновь произойдет ошибка выполнения, потому что каждый контейнер <asp:Content></asp:Content> обязательно должен ссылаться на свою именованную область в подключенном шаблоне в соотношении "один к одному". Только через прикрепленную именованную область содержимое контейнера может появиться на странице и именно в том месте, где эту область зарезервирует шаблон.

  • Откройте на редактирование файл ~/MasterPages/FirstMasterPage.master в режиме Design и поместите на шаблон из вкладки Standard элемент управления ContentPlaceHolder, экземпляр которого мы ранее удалили
  • Перейдите в режим Source на странице FirstMasterPage.master и поместите внутрь созданного контейнера ContentPlaceHolder1 текстовую строку, чтобы дескрипторный код стал таким
<%@ Master Language="C#" AutoEventWireup="true" 
    CodeFile="FirstMasterPage.master.cs" 
    Inherits="FirstMasterPage" %>
  
<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">
            <h1>Привет студентам из "именованной области1" мастер-страницы!</h1>
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>
Листинг 31.31. Дескрипторный код шаблона FirstMasterPage.master
  • Перейдите в режим Design и убедитесь, что именованная область шаблона приобрела свое собственное содержимое


Теперь нужно настроить контекстную страницу, использующую шаблон.

  • Откройте на редактирование в режиме Source контекстную страницу FirstMasterPage.aspx, к которой подключен шаблон, и определите в контейнере <asp:Content> идентификатор-ссылку ContentPlaceHolderID резервируемой области шаблона, на которую будет ссылаться контекстный дескриптор

Пользуйтесь услугами подсказчика кода IntelliSense, который вызывается каждый раз при добавлении пробела внутри дескриптора. Идентификатор ID самого контейнера <asp:Content> в контекстной странице определять необязательно, если только мы не планируем управлять им программно. Измененный код будет таким

<%@ Page Language="C#" 
    MasterPageFile="~/MasterPages/FirstMasterPage.master" 
    AutoEventWireup="true" CodeFile="FirstMasterPage.aspx.cs" 
    Inherits="FirstMasterPage" Title="Тестовая страница содержимого" %>
    
<%-- Add content controls here --%>
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <h1>Привет студентам из "страницы содержимого1"!</h1>
</asp:Content>
Листинг 31.32. Контейнер содержимого на странице FirstMasterPage.aspx
  • Исполните страницу FirstMasterPage.aspx, должен получиться такой результат с учетом действия темы MyTheme, подключенной в конфигурационном файле корня Web-дерева


  • Поместите на шаблон еще один резервирующий контейнер ContentPlaceHolder и наполните его таким кодом
<%@ Master Language="C#" AutoEventWireup="true" 
    CodeFile="FirstMasterPage.master.cs" 
    Inherits="FirstMasterPage" %>
  
<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">
            <h1>Привет студентам из "именованной области1" мастер-страницы!</h1>
        </asp:ContentPlaceHolder>
        <br />
        <asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server">
            <h1>Привет студентам из "именованной области2" мастер-страницы!</h1>
        </asp:ContentPlaceHolder>
    </div>
    </form>
</body>
</html>
Листинг 31.33. Дескрипторный код шаблона FirstMasterPage.master
  • Перейдите на контекстную страницу FirstMasterPage.aspx в режиме Design, которая станет такой


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

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

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

Обратите внимание на заголовки именованных областей и их фон. Там, где подставлено содержимое прикрепленного контейнера, фон светлее и в скобках надпись ( Custom ) - заказной. Там, где проявилось содержимое мастер-страницы, фон темнее и надпись ( Master ).

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

  • На странице FirstMasterPage.aspx в режиме Design вызовите контекстное меню для нижней зарезервированной области и выполните команду Create Custom Content

Оболочка добавит пустой контейнер содержимого и автоматически свяжет его в дескрипторном коде с именованной резервируемой областью.

  • Добавьте в контейнер с содержимым какой-нибудь текст и несколько компонентов из панели Toolbox и выполните страницу

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

После того, как на вновь созданной странице с содержимым проявятся именованные области шаблона, их можно переопределить и заполнить, создав командой контекстного меню Create Custom Content контейнеры индивидуального содержимого. Удалить контейнер содержимого можно командой Default to Master's Content.

  • На нижней области контекстной страницы FirstMasterPage.aspx вызовите контекстное меню и выполните команду Default to Master's Content, чтобы удалить содержимое

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

Упражнение 14. Применение усложненной мастер-страницы

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

Иван Циферблат
Иван Циферблат
Россия, Таганрог, 36, 2000