Вложенные основные страницы (C#)

Скотт Митчелл

Показывает, как вложить одну главную страницу в другую.

Введение

За время последних девяти уроков мы научились, как реализовать макет на уровне сайта с основными страницами. Короче говоря, мастер-страницы позволяют нам, разработчикам страниц, задавать общую разметку на мастер-странице вместе с определенными областями, которые можно настроить для каждой страницы контента. Элементы управления ContentPlaceHolder на главной странице указывают настраиваемые регионы; Настраиваемая разметка для элементов управления ContentPlaceHolder определяется на странице содержимого с помощью элементов управления Content.

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

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

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

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

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

Примечание.

Вложенные главные страницы были возможны с версии 2.0, .NET Framework. Однако Visual Studio 2005 не включал поддержку времени разработки для вложенных главных страниц. Хорошая новость заключается в том, что Visual Studio 2008 предлагает богатые возможности в режиме проектирования для вложенных мастер-страниц. Если вы хотите использовать вложенные мастер-страницы, но по-прежнему используете Visual Studio 2005, ознакомьтесь с записью в блоге Скотта Гатри "Советы по использованию вложенных мастер-страниц в среде разработки VS 2005".

Преимущества иерархических главных страниц

Многие веб-сайты имеют общий дизайн, а также более индивидуальные дизайны, относящиеся к определенным типам страниц. Например, в демонстрационном веб-приложении мы создали раздел администрирования (страницы в папке ~/Admin ). В настоящее время веб-страницы в ~/Admin папке используют ту же главную страницу, что и те страницы, которые не находятся в разделе администрирования (а именно или Site.masterAlternate.masterв зависимости от выбора пользователя).

Примечание.

На данный момент, притворяйтесь, что наш сайт имеет только одну главную страницу, Site.master. Мы будем использовать вложенные главные страницы с двумя (или более) эталонными страницами, начиная с раздела "Использование вложенной главной страницы для раздела администрирования" далее в этом руководстве.

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

  1. Вручную добавьте сведения об администрации и ссылки на каждую страницу содержимого в папке ~/Admin.
  2. Site.master Обновите эталонную страницу, чтобы включить сведения и ссылки для раздела администрирования, а затем добавьте код на главную страницу, чтобы отобразить или скрыть эти разделы на основе того, просматривается ли одна из страниц администрирования.
  3. Создайте главную страницу специально для раздела администрирования, скопируйте разметку из Site.master, добавьте сведения и ссылки для раздела администрирования, а затем обновите страницы содержимого в папке ~/Admin , чтобы использовать эту новую эталонную страницу.
  4. Создайте вложенную главную страницу, которая привязывается Site.master и содержит страницы содержимого в папке ~/Admin , используйте эту новую вложенную главную страницу. Эта вложенная эталонная страница будет содержать только дополнительные сведения и ссылки, относящиеся к страницам администрирования, и не потребуется повторять разметку, уже определенную в Site.master.

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

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

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

В этом руководстве рассматривается создание и использование простой вложенной главной страницы. Мы создадим новую эталонную страницу верхнего уровня, две вложенные главные страницы и две страницы содержимого. Начиная с статьи "Использование вложенной главной страницы для раздела администрирования", мы рассмотрим обновление существующей архитектуры главной страницы, чтобы включить использование вложенных главных страниц. В частности, мы создадим вложенную главную страницу и используем ее для включения дополнительного пользовательского содержимого для страниц содержимого в папку ~/Admin .

Шаг 1. Создание простой главной страницы верхнего уровня

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

Создайте новую папку с именем NestedMasterPagesSimple.master, а затем добавьте в нее новый главный файл страницы. (См. рисунок 1 для снимка экрана Обозревателя решений после добавления этой папки и файла.) Перетащите файл таблицы стилей AlternateStyles.css из Обозревателя решений на конструктор. Это добавляет элемент <link> в файл таблицы стилей внутри элемента <head>, после чего разметка элемента главной страницы <head> должна выглядеть следующим образом:

<head runat="server">
 <title>Untitled Page</title> 
 <asp:ContentPlaceHolder id="head" runat="server"> 
 </asp:ContentPlaceHolder>
 <link href="../AlternateStyles.css" rel="stylesheet" type="text/css" /> 
</head>

Затем добавьте следующую разметку в веб-форме Simple.master:

<div id="topContent"> 
 <asp:HyperLink ID="lnkHome" runat="server" 
 NavigateUrl="~/NestedMasterPages/Default.aspx"
 Text="Nested Master Pages Tutorial (Simple)" /> 
</div> 
<div id="mainContent"> 
 <asp:ContentPlaceHolder id="MainContent" runat="server"> 
 </asp:ContentPlaceHolder>
</div>

Эта разметка отображает ссылку с названием "Вложенные главные страницы (простые)" в верхней части страницы в большом белом шрифте на тёмно-синем фоне. Под этим находится MainContent ContentPlaceHolder. На рисунке 1 показана главная Simple.master страница при загрузке в конструктор Visual Studio.

Основная страница Simple dot при загрузке в конструктор Visual Studio.

Рис. 01. Вложенная главная страница определяет содержимое для страниц в разделе администрирования (щелкните, чтобы просмотреть изображение полного размера)

Шаг 2. Создание простой вложенной главной страницы

Simple.master содержит два элемента управления ContentPlaceHolder: MainContent ContentPlaceHolder, добавленный в веб-форму, и head ContentPlaceHolder, находящийся в элементе <head>. Если бы мы создали страницу содержимого и привязали ее к Simple.master, то страница содержимого имела бы два элемента управления "Содержимое", которые ссылаются на два "ContentPlaceHolders". Аналогичным образом, если мы создадим вложенную главную страницу и привяжем ее к Simple.master, вложенная главная страница будет иметь два элемента управления Content.

Давайте добавим новую вложенную главную страницу в папку NestedMasterPages с именем SimpleNested.master. Щелкните правой кнопкой мыши папку NestedMasterPages и выберите пункт "Добавить новый элемент". Откроется диалоговое окно "Добавление нового элемента", показанное на рис. 2. Выберите тип шаблона главной страницы и введите имя новой главной страницы. Чтобы указать, что новая эталонная страница должна быть вложенной главной страницей, установите флажок "Выбрать главную страницу".

Затем нажмите кнопку "Добавить". Откроется то же диалоговое окно "Выбор главной страницы", которое отображается при привязке страницы содержимого к главной странице (см. рис. 3). Выберите главную Simple.master страницу в папке NestedMasterPages и нажмите кнопку "ОК".

Примечание.

Если вы создали веб-сайт ASP.NET с помощью модели проекта веб-приложения, а не модели проекта веб-сайта, то вы не увидите флажок "Выбор главной страницы" в диалоговом окне "Добавить новый элемент", показанном на рис. 2. Чтобы создать вложенную главную страницу при использовании модели проекта веб-приложения, необходимо выбрать шаблон вложенной главной страницы (вместо шаблона главной страницы). После выбора шаблона вложенной главной страницы и нажатия кнопки "Добавить" откроется то же диалоговое окно "Выбор главной страницы", показанное на рис. 3.

Установите флажок

Рис. 02. Установите флажок "Выбор главной страницы", чтобы добавить вложенную главную страницу (щелкните, чтобы просмотреть изображение полного размера)

Привязка вложенной главной страницы к главной странице Simple.master

Рис. 03. Привязка вложенной главной страницы к Simple.master главной странице (щелкните, чтобы просмотреть изображение полного размера)

Декларативная разметка вложенной мастер-страницы, показанная ниже, содержит два элемента управления Content, которые ссылаются на два элемента управления ContentPlaceHolder на верхнем уровне.

<%@ Master Language="C#" MasterPageFile="~/NestedMasterPages/Simple.master" AutoEventWireup="false" CodeFile="SimpleNested.master.cs" Inherits="NestedMasterPages_SimpleNested" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server"> 
 </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 </asp:Content>

<%@ Master %> За исключением директивы, начальная декларативная разметка вложенной главной страницы идентична разметке, которая изначально создается при привязке страницы содержимого к той же главной странице верхнего уровня. Как и директива <%@ Page %> страницы содержимого, директива <%@ Master %> здесь включает атрибут MasterPageFile, указывающий на родительскую главную страницу для вложенной главной страницы. Основное различие между вложенной главной страницей и страницей содержимого, привязанной к той же главной странице верхнего уровня, заключается в том, что вложенные главные страницы могут включать элементы управления ContentPlaceHolder. Элементы управления ContentPlaceHolder на вложенной основной странице определяют области, где страницы контента могут адаптировать разметку.

Обновите эту вложенную мастер-страницу, чтобы она отображала текст "Hello, from SimpleNested!" в элементе управления "Содержимое", соответствующем элементу MainContent управления ContentPlaceHolder.

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 <p>Hello, from SimpleNested!</p>
</asp:Content>

После добавления сохраните вложенную главную страницу и добавьте новую страницу содержимого в NestedMasterPages папку с именем Default.aspxи привязать ее к главной SimpleNested.master странице. После добавления этой страницы вы можете быть удивлены, чтобы увидеть, что он не содержит элементов управления содержимым (см. рис. 4)! Страница содержимого может получить доступ только к ContentPlaceHolders родительской главной страницы. SimpleNested.master не содержит элементов управления ContentPlaceHolder; Таким образом, любая страница содержимого, привязанная к этой главной странице, не может содержать элементы управления содержимым.

Новая страница содержимого не содержит элементов управления содержимым

Рис. 04. Страница нового содержимого не содержит элементов управления содержимым (щелкните, чтобы просмотреть изображение полного размера)

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

Обновите главную SimpleNested.master страницу, добавив ContentPlaceHolder в её два элемента управления Content. Присвойте управляющему элементу ContentPlaceHolder то же имя, что и управляющему элементу ContentPlaceHolder, на который ссылается их управляющий элемент Content. То есть добавьте элемент управления ContentPlaceHolder с именем MainContent в элемент управления SimpleNested.master Content, который ссылается на MainContent ContentPlaceHolder в Simple.master. Выполните то же самое в элементе управления "Контент", который ссылается на head ContentPlaceHolder.

Примечание.

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

После добавления этих дополнений декларативная разметка главной SimpleNested.master страницы должна выглядеть примерно так:

<%@ Master Language="C#" MasterPageFile="~/NestedMasterPages/Simple.master"AutoEventWireup="false" CodeFile="SimpleNested.master.cs" Inherits="NestedMasterPages_SimpleNested" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server"> 
 <asp:ContentPlaceHolder ID="head" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 <p>Hello, from SimpleNested!</p>
 <asp:ContentPlaceHolder ID="MainContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content>

Удалите только что созданную страницу содержимого Default.aspx и повторно добавьте ее, привязав ее к главной SimpleNested.master странице. На этот раз Visual Studio добавляет два элемента управления Content в Default.aspx, ссылающиеся на сейчас определенные ContentPlaceHolders в SimpleNested.master (см. рис. 6). Добавьте текст "Hello, from Default.aspx!" в элемент управления "Содержимое", который ссылается на MainContent.

На рисунке 5 показаны три сущности, участвующие здесь - Simple.master, SimpleNested.master и Default.aspx - и как они связаны друг с другом. Как показано на схеме, вложенная главная страница реализует элементы управления контентом для ContentPlaceHolder своего родительского элемента. Если эти области должны быть доступны для страницы содержимого, вложенная главная страница должна добавить собственные элементы ContentPlaceHolders в элементы управления Content.

Верхний уровень и вложенные главные страницы определяют макет страницы содержимого

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

Это поведение иллюстрирует, как страница содержимого или основная страница осознают только свою родительскую основную страницу. Это поведение также указывается конструктором Visual Studio. На рисунке 6 показан дизайнер для Default.aspx. Хотя Designer четко показывает, какие области редактируемы на странице содержимого и какие части нет, он не уточняет, какие нередактируемые области принадлежат вложенной мастер-странице, а какие относятся к мастер-странице верхнего уровня.

Страница содержимого теперь включает элементы управления содержимым для вложенных главных страниц ContentPlaceHolders

Рис. 06. Страница содержимого теперь включает элементы управления содержимым для вложенных главных страниц ContentPlaceHolders (щелкните, чтобы просмотреть изображение полного размера)

Шаг 3. Добавление второй простой вложенной главной страницы

Преимущество вложенных главных страниц более очевидно при наличии нескольких вложенных главных страниц. Чтобы проиллюстрировать это преимущество, создайте в папке NestedMasterPages другую вложенную главную страницу; присвойите ей имя новой вложенной главной страницы SimpleNestedAlternate.master и привязать ее к главной Simple.master странице. Добавьте элементы управления ContentPlaceHolder в два элемента управления Content на вложенной главной странице, так же как мы сделали на шаге 2. Кроме того, добавьте текст "Hello, from SimpleNestedAlternate!" в элементе управления "Контент", соответствующем главной странице MainContent верхнего уровня ContentPlaceHolder. После внесения этих изменений декларативная разметка новой вложенной главной страницы должна выглядеть следующим образом:

<%@ Master Language="C#" MasterPageFile="~/NestedMasterPages/Simple.master" AutoEventWireup="false" CodeFile="SimpleNestedAlternate.master.cs" Inherits="NestedMasterPages_SimpleNestedAlternate" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">
 <asp:ContentPlaceHolder ID="head" runat="server">
 </asp:ContentPlaceHolder> 
 </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
 <p>Hello, from SimpleNestedAlternate!</p> 
 <asp:ContentPlaceHolder ID="MainContent" runat="server">
 </asp:ContentPlaceHolder> 
 </asp:Content>

Создайте страницу содержимого с именем Alternate.aspx в папке NestedMasterPages и привязать ее к вложенной главной SimpleNestedAlternate.master странице. Добавьте текст "Hello, from Alternate!" в элемент управления содержимым, соответствующий MainContent. На рисунке 7 показано Alternate.aspx при просмотре с помощью конструктора Visual Studio.

Alternate.aspx привязан к главной странице SimpleNestedAlternate.master

Рис. 07: Alternate.aspx принадлежит главной SimpleNestedAlternate.master странице (щелкните, чтобы увидеть изображение в полном размере)

Сравните конструктор на рис. 7 с конструктором на рис. 6. Обе страницы содержимого используют одинаковый макет, определенный на главной странице верхнего уровня (Simple.master), а именно название "Учебник по вложенным главным страницам (простой)". Оба обладают различным содержимым, определённым на родительских мастер-страницах, текст "Hello, from SimpleNested!" на рисунке 6 и "Hello, from SimpleNestedAlternate!" на рисунке 7. Да, эти различия здесь тривиальные, но вы можете расширить этот пример, чтобы включить более значимые различия. Например, страница SimpleNested.master может включать меню с параметрами, относящимися к его страницам содержимого, в то время как SimpleNestedAlternate.master может иметь сведения, относящиеся к страницам содержимого, которые привязываются к нему.

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

Чтобы продемонстрировать простоту, с помощью которой можно изменить макет сайта, откройте Simple.master главную страницу и добавьте следующую разметку между элементами topContentmainContent<div>:

<div id="navContent"> 
 <asp:HyperLink ID="lnkDefault" runat="server" 
 NavigateUrl="~/NestedMasterPages/Default.aspx" 
 Text="Nested Master Page Example 1" /> 
 | 
 <asp:HyperLink ID="lnkAlternate" runat="server" 
 NavigateUrl="~/NestedMasterPages/Alternate.aspx" 
 Text="Nested Master Page Example 2" /> 
</div>

Это добавляет две ссылки на верхнюю часть каждой страницы, которая привязывается к Simple.master, SimpleNested.masterили SimpleNestedAlternate.master; эти изменения применяются ко всем вложенным главным страницам и их страницам содержимого немедленно. На рисунке 8 показано Alternate.aspx при просмотре через браузер. Обратите внимание на добавление ссылок в верхней части страницы (по сравнению с рис. 7).

Изменения в мастер-странице верхнего уровня немедленно отражаются на вложенных мастер-страницах и их страницах содержимого

Рис. 08. Изменение главной страницы верхнего уровня немедленно отражается на вложенных главных страницах и их страницах содержимого (щелкните, чтобы просмотреть изображение полного размера)

Использование вложенной главной страницы для раздела администрирования

На этом этапе мы рассмотрели преимущества вложенных главных страниц и видели, как создавать и использовать их в приложении ASP.NET. Однако примеры в шагах 1, 2 и 3 включали создание новой главной страницы верхнего уровня, новых вложенных главных страниц и новых страниц контента. Что делать с добавлением новой вложенной главной страницы на веб-сайт с существующей главной страницей верхнего уровня и страницами содержимого?

Интеграция вложенной главной страницы в существующий веб-сайт и связывание ее с существующими страницами контента требует немного больше усилий, чем начиная с нуля. Шаги 4, 5, 6 и 7 рассматривают эти проблемы по мере расширения демонстрационного приложения, чтобы включить новую вложенную главную страницу AdminNested.master , содержащую инструкции администратора и используемые страницами ASP.NET в папке ~/Admin .

Интеграция вложенной главной страницы в демонстрационное приложение представляет следующие препятствия:

  • Существующие страницы содержимого в папке ~/Admin имеют определенные ожидания от главной страницы. Для начала они ожидают, что некоторые элементы управления ContentPlaceHolder будут присутствовать. Кроме того, страницы ~/Admin/AddProduct.aspx~/Admin/Products.aspx вызывают открытый RefreshRecentProductsGrid метод главной страницы, задают его GridMessageText свойство или имеют обработчик событий для его PricesDoubled события. Следовательно, вложенная главная страница должна предоставлять одинаковые элементы ContentPlaceHolders и общедоступных участников.
  • В предыдущем руководстве мы улучшили функциональность класса BasePage, чтобы динамически задавать свойство MasterPageFile объекта Page на основе переменной сеанса. Как поддерживать динамические главные страницы при использовании вложенных главных страниц?

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

Шаг 4. Создание вложенной главной страницы

Наша первая задача — создать вложенную главную страницу, которая будет использоваться страницами в разделе администрирования. Как мы видели на шаге 2, при добавлении новой вложенной главной страницы необходимо указать родительскую главную страницу вложенной главной страницы. Но у нас есть две главные страницы верхнего уровня: Site.master и Alternate.master. Помните, что мы создали Alternate.master в предыдущем руководстве и написали код в классе BasePage, который задает свойство объекта Page MasterPageFile во время выполнения в Site.master или Alternate.master в зависимости от значения переменной сеанса MyMasterPage.

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

  • Создайте две вложенные главные страницы AdminNestedSite.master и AdminNestedAlternate.master, и привяжите их к главным страницам верхнего уровня Site.master и Alternate.master соответственно. В BasePage затем мы задали Page объекту MasterPageFile соответствующую вложенную главную страницу.
  • Создайте вложенную основную страницу и настройте страницы содержимого для использования этой конкретной основной страницы. Затем во время выполнения необходимо задать для свойства вложенной главной страницы MasterPageFile соответствующую верхнеуровневую главную страницу. (Как вы могли бы понять, к настоящему моменту главные страницы также имеют MasterPageFile свойство.)

Давайте будем использовать второй вариант. Создайте один вложенный главный файл страницы в папке ~/Admin с именем AdminNested.master. Site.master и Alternate.master имеют один и тот же набор элементов управления ContentPlaceHolder, поэтому не имеет значения, к какой главной странице вы его привязываете. Однако, ради согласованности, я рекомендую привязать его к Site.master.

Добавьте вложенную главную страницу в папку ~/Admin.

Рис. 09: Добавьте вложенную главную страницу в папку ~/Admin. (Щелкните, чтобы просмотреть изображение полного размера)

Поскольку вложенная основная страница привязана к основной странице с четырьмя элементами управления ContentPlaceHolder, Visual Studio добавляет четыре элемента управления Content в начальную разметку нового вложенного основного файла. Как и в шагах 2 и 3, добавьте элемент управления ContentPlaceHolder в каждом элементе управления Content, дав ему то же имя, что и элемент управления ContentPlaceHolder на главной странице верхнего уровня. Кроме того, добавьте следующую разметку в элемент управления Content, соответствующий MainContent ContentPlaceHolder:

<div class="instructions"> 
 <b>Administration Instructions:</b>
 <br /> 
 The pages in the Administration section allow you, the Administrator, to 
 add new products and view existing products. 
</div>

Затем определите instructions класс CSS в файлах Styles.css CSS и AlternateStyles.css CSS. Следующие правила CSS заставляют HTML-элементы, стилизованные с помощью класса instructions, отображаться с фоном светло-жёлтого цвета и чёрной сплошной границей.

.instructions 
{ 
 padding: 6px; 
 border: dashed 1px black; 
 background-color: #ffb; 
 margin-bottom: 10px; 
}

Так как эта разметка была добавлена на вложенную главную страницу, она будет отображаться только на тех страницах, которые используют эту вложенную главную страницу (а именно страницы в разделе администрирования).

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

<%@ Master Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="false" CodeFile="AdminNested.master.cs" Inherits="Admin_AdminNested" %> 
 <asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server"> 
 <asp:ContentPlaceHolder ID="head" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> 
 <div class="instructions">
 <b>Administration Instructions:</b>
 <br /> 
 The pages in the Administration section allow you, the Administrator, to 
 add new products and view existing products. 
 </div> 
 <asp:ContentPlaceHolder ID="MainContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content3" ContentPlaceHolderID="QuickLoginUI" Runat="Server"> 
 <asp:ContentPlaceHolder ID="QuickLoginUI" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content> 
 <asp:Content ID="Content4" ContentPlaceHolderID="LeftColumnContent" Runat="Server"> 
 <asp:ContentPlaceHolder ID="LeftColumnContent" runat="server"> 
 </asp:ContentPlaceHolder>
 </asp:Content>

Обратите внимание, что каждый элемент управления Content содержит элемент управления ContentPlaceHolder, и свойства элементов управления ID ContentPlaceHolder получают такие же значения, что и соответствующие элементы управления ContentPlaceHolder на основной странице верхнего уровня. Кроме того, разметка раздела администрирования отображается в MainContent ContentPlaceHolder.

На рисунке 10 показана AdminNested.master вложенная главная страница при просмотре с помощью конструктора Visual Studio. Инструкции можно просмотреть в желтом поле в верхней части MainContent элемента управления "Содержимое".

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

Рис. 10. Вложенная главная страница расширяет эталонную страницу верхнего уровня, чтобы включить инструкции администратора. (Щелкните, чтобы просмотреть изображение полного размера)

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

В любой момент, когда мы добавим новую страницу содержимого в раздел администрирования, необходимо привязать ее к главной AdminNested.master странице, которую мы только что создали. Но как насчет существующих страниц содержимого? В настоящее время все страницы контента на сайте являются производными от BasePage класса, который программно задает главную страницу страницы контента во время выполнения. Это не поведение, которое мы хотим использовать для страниц содержимого в разделе администрирования. Вместо этого мы хотим, чтобы эти страницы содержимого всегда использовали страницу AdminNested.master . Отвечать за выбор правильной страницы содержимого верхнего уровня во время выполнения будет вложенная мастер-страница.

Для достижения этого желаемого поведения рекомендуется создать новый пользовательский базовый класс страницы с именем AdminBasePage , расширяющим BasePage класс. AdminBasePage затем можно переопределить SetMasterPageFile и задать Page для объекта MasterPageFile жестко закодированное значение "~/Admin/AdminNested.master". Таким образом, любая страница, наследуемая от AdminBasePage, будет использовать AdminNested.master, в то время как любая страница, наследуемая от BasePage, будет иметь свойство MasterPageFile, установлено динамически как "~/Site.master" или "~/Alternate.master" в зависимости от значения переменной сеанса MyMasterPage.

Начните с добавления нового файла класса в папку App_Code с именем AdminBasePage.cs. Пускай AdminBasePage расширяет BasePage, а затем переопределяет метод SetMasterPageFile. В этом методе присвойте MasterPageFile значение "~/Admin/AdminNested.master". После внесения этих изменений файл класса должен выглядеть следующим образом:

public class AdminBasePage : BasePage 
{ 
    protected override void SetMasterPageFile() 
    { 
        this.MasterPageFile = "~/Admin/AdminNested.master"; 
    } 
}

Теперь необходимо, чтобы существующие страницы содержимого в разделе администрирования происходили из AdminBasePage вместо BasePage. Перейдите к файлу класса code-behind для каждой страницы содержимого в папке ~/Admin и внесите это изменение. Например, в ~/Admin/Default.aspx следует изменить объявление класса 'code-behind':

public partial class Admin_Default : BasePage

Кому:

public partial class Admin_Default : AdminBasePage

На рисунке 11 показано, как эталонная страница верхнего уровня (Site.master или Alternate.master), вложенные главные страницы (AdminNested.master) и страницы содержимого раздела администрирования связаны друг с другом.

Вложенная главная страница определяет содержимое, относяемое к страницам в разделе администрирования

Рис. 11. Вложенная главная страница определяет содержимое для страниц в разделе администрирования (щелкните, чтобы просмотреть изображение полного размера)

Шаг 6. Зеркальное отображение общедоступных методов и свойств главной страницы

Помните, что страницы ~/Admin/AddProduct.aspx и ~/Admin/Products.aspx взаимодействуют программно с главной страницей: ~/Admin/AddProduct.aspx вызывает открытый метод RefreshRecentProductsGrid главной страницы и устанавливает свойство GridMessageText главной страницы. ~/Admin/Products.aspx имеет обработчик событий для события PricesDoubled. В предыдущем руководстве мы создали абстрактный BaseMasterPage класс, определяющий эти открытые члены.

Страницы ~/Admin/AddProduct.aspx и ~/Admin/Products.aspx предполагают, что их главная страница является производной от класса BaseMasterPage. Однако страница AdminNested.master в настоящее время расширяет System.Web.UI.MasterPage класс. В результате при посещении ~/Admin/Products.aspxInvalidCastException выбрасывается исключение с сообщением: "Не удается привести объект типа 'ASP.admin_adminnested_master' к типу 'BaseMasterPage'."

Чтобы устранить эту проблему, необходимо расширить AdminNested.master класс BaseMasterPagecode-behind. Обновите объявление класса, связанного с кодом, вложенной главной страницы из:

public partial class Admin_AdminNested : System.Web.UI.MasterPage

Кому:

public partial class Admin_AdminNested : BaseMasterPage

Мы еще не закончили. Так как класс BaseMasterPage является абстрактным, необходимо переопределить элементы abstract, RefreshRecentProductsGrid и GridMessageText. Эти элементы используются главными страницами верхнего уровня для обновления пользовательских интерфейсов. (На самом деле только главная страница Site.master использует эти методы, хотя обе главные страницы верхнего уровня реализуют эти методы, так как обе расширяют BaseMasterPage.)

Хотя нам нужно реализовать эти члены в AdminNested.master, всё, что необходимо сделать во всех этих реализациях, — это просто вызвать тот же член на главной странице верхнего уровня, используемой вложенной главной страницей. Например, когда страница содержимого в разделе администрирования вызывает метод вложенной главной страницыRefreshRecentProductsGrid, все вложенные главные страницы должны выполняться, в свою очередь, вызов Site.master или Alternate.masterRefreshRecentProductsGrid метод.

Для этого сначала добавьте следующую @MasterType директиву в начало AdminNested.master:

<%@ MasterType TypeName="BaseMasterPage" %>

Помните, что директива @MasterType добавляет строго типизированное свойство в класс code-behind с именем Master. Затем переопределите члены RefreshRecentProductsGrid и GridMessageText, а затем просто делегируйте вызов соответствующему методу Master.

public partial class Admin_AdminNested : BaseMasterPage 
{ 
    public override void RefreshRecentProductsGrid() 
    { 
        Master.RefreshRecentProductsGrid();
    } 
    public override string GridMessageText
    { 
        get 
        {
            return Master.GridMessageText;
        } 
        set
        { 
            Master.GridMessageText = value; 
        } 
    }
}

С использованием этого кода, вы сможете посещать и использовать страницы контента в разделе Администрирование. На рисунке 12 показана ~/Admin/Products.aspx страница при просмотре через браузер. Как видно, на странице содержится поле "Инструкции администрирования", которое определено на вложенной главной странице.

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

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

Шаг 7. Использование соответствующей главной страницы верхнего уровня во время выполнения

Хотя все страницы содержимого в разделе администрирования полностью функциональны, они используют одну и ту же главную страницу верхнего уровня и игнорируют главную страницу, выбранную пользователем ChooseMasterPage.aspx. Это происходит из-за того, что вложенная главная страница имеет свойство MasterPageFile, статически установленное на Site.master в директиве <%@ Master %>.

Чтобы использовать главную страницу верхнего уровня, выбранную конечным пользователем, необходимо задать свойство MasterPageFile элемента AdminNested.master значением переменной MyMasterPage сеанса. Так как мы устанавливаем свойства страниц содержимого в MasterPageFile, вы можете подумать, что мы задали бы свойство вложенной главной страницы в MasterPageFile в BaseMasterPage или в классе программной части AdminNested.master. Однако это не будет работать, поскольку свойство MasterPageFile должно быть задано к концу стадии PreInit. Самое раннее время, которое мы можем программным способом подключиться к жизненному циклу страницы с главной страницы, — это этап Init (который происходит после этапа PreInit).

Поэтому необходимо задать свойство вложенной главной страницы MasterPageFile на страницах содержимого. Единственные страницы содержимого, использующие основную AdminNested.master страницу, основаны на AdminBasePage. Поэтому мы можем поместить эту логику туда. На шаге 5 мы переопределили метод SetMasterPageFile, установив свойству MasterPageFile объекта Page значение "~/Admin/AdminNested.master". Обновите SetMasterPageFile, чтобы также задать свойство MasterPageFile главной страницы результатом, сохраняемым в сеансе:

public class AdminBasePage : BasePage 
{ 
    protected override void SetMasterPageFile() 
    { 
        this.MasterPageFile = "~/Admin/AdminNested.master"; 
        Page.Master.MasterPageFile = base.GetMasterPageFileFromSession(); 
    } 
}

Метод GetMasterPageFileFromSession , который мы добавили в BasePage класс в предыдущем руководстве, возвращает соответствующий путь к файлу главной страницы на основе значения переменной сеанса.

В результате этого изменения выбор главной страницы пользователя будет применяться в разделе администрирования. На рисунке 13 показана та же страница, что и на рис. 12, но после изменения выбора Alternate.masterглавной страницы пользователя.

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

Рис. 13. Страница вложенного администрирования использует эталонную страницу верхнего уровня, выбранную пользователем (щелкните, чтобы просмотреть изображение полного размера)

Итоги

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

Счастливое программирование!

Дополнительные материалы

Дополнительные сведения о разделах, описанных в этом руководстве, см. в следующих ресурсах:

Об авторе

Скотт Митчелл, автор нескольких книг ASP/ASP.NET и основатель 4GuysFromRolla.com, работает с технологиями Microsoft Web с 1998 года. Скотт работает независимым консультантом, тренером и писателем. Его последняя книга Изучите ASP.NET 3.5 за 24 часа с помощью Сэмс. С Скоттом можно связаться на mitchell@4GuysFromRolla.com или через его блог http://ScottOnWriting.NET.

Особое спасибо кому

Эта серия учебников была проверена многими полезными рецензентами. Хотите просмотреть мои предстоящие статьи MSDN? Если да, напишите мне на mitchell@4GuysFromRolla.com