Украина, Киев |
Стилевое оформление страниц
Первый способ
- Двойным щелчком на свободном от элементов управления месте мастер-страницы Title.master в режиме Design (или вручную) создайте блок скриптов, который заполните так
<%@ Master Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { } public string MyHeader1 { get { return Header1.InnerText; } set { Header1.InnerText = value; } } </script> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Мастер-страница Title.master</title> </head> <body> <form id="form1" runat="server"> <div style="text-align: center"> <asp:Image ID="ImageBanner" runat="server" ImageUrl="~/MasterPages/Banner.png" /> <h1 style="color: Green" runat="server" id="Header1"> Мы приветствуем Вас на нашем сайте!!! </h1> ............................................. </div> </form> </body> </html>Листинг 31.54. Добавление свойства доступа к дескриптору <h1> в файле Title.master
- Дополните контекстную страницу SatelliteExt.aspx следующим кодом
<%@ Page Language="C#" MasterPageFile="~/MasterPages/Title.master" Title="Декларативный заголовок SatelliteExt.aspx" %> <%@ MasterType VirtualPath="~/MasterPages/Title.master" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { // Получаем ссылку на мастер-страницу Page masterPage = Master.Page; // Переопределяем строку заголовка masterPage.Header.Title = "Программный заголовок SatelliteExt.aspx"; // Управляем дескриптором h1 Master.MyHeader1 = "Это программно подмененный" + " заголовок мастер-страницы (способ 1)!"; } </script>Листинг 31.55. Дополненный код контекстной страницы SatelliteExt.aspx
- Исполните контекстную страницу SatelliteExt.aspx и убедитесь, что дескриптор <h1>, относящийся к заполнителю мастер-страницы, подменяется нашим текстом
Директива @ MasterType указывает ASP.NET виртуальный путь к соответствующему файлу мастер-страницы. Без нее доступ к объявленному свойству будет неопределен.
Второй способ
- Измените контекстную страницу SatelliteExt.aspx следующим образом
<%@ Page Language="C#" MasterPageFile="~/MasterPages/Title.master" Title="Декларативный заголовок SatelliteExt.aspx" %> <%@ MasterType VirtualPath="~/MasterPages/Title.master" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { // Получаем ссылку на мастер-страницу Page masterPage = Master.Page; // Переопределяем строку заголовка masterPage.Header.Title = "Программный заголовок SatelliteExt.aspx"; // Управляем дескриптором h1 // Master.MyHeader1 = "Это программно подмененный" // + " заголовок мастер-страницы (способ 1)!"; HtmlGenericControl h1 = Master.FindControl("Header1") as HtmlGenericControl; if (h1 != null) { h1.InnerText = "Это программно подмененный" + " заголовок мастер-страницы (способ 2)!"; } } </script>Листинг 31.56. Измененный код контекстной страницы SatelliteExt.aspx
Метод FindControl() ищет указанный элемент на мастер-странице среди элементов заданного типа, и если находит, то возвращает контекстной странице ссылку на этот элемент. Затем уже мы обращаемся к конкретным свойствам этого элемента.
- Исполните страницу SatelliteExt.aspx и убедитесь, что дескриптор <h1>, относящийся к заполнителю мастер-страницы, подменяется нашим текстом
Второй способ более предпочтительный, поскольку мы не вмешиваемся в код спроектированной мастер-страницы, которая может быть подключена еще к чему-нибудь. Мы в мастер-странице просто заранее преобразуем некоторые элементы в серверные (управляемые на стороне сервера) и присваиваем им идентификаторы для дальнейшей адресации из кода контекстной страницы.
Упражнение 16. Программное переключение мастер-страниц
Иногда может возникнуть необходимость дать возможность пользователю подключать необходимые мастер-страницы. Мы уже рассматривали подобный способ, когда говорили о динамическом подключении тем. Там мы программно определяли значение атрибута Page.Theme в директиве @Page. Теперь нам нужно программно менять атрибут Page.MasterPageFile в коде контекстной страницы.
Здесь нужно иметь ввиду следующее:
- Контекстная страница, динамически меняющая шаблон, не должна иметь контекстных блоков, ссылающихся на несуществующие в новой мастер-странице контейнеры ContentPlaceHolderID
- Замена шаблона должна выполняться в обработчике события Page.PreInit контекстной страницы. Если это сделать в обработчиках более поздних событий, то будет сгенерировано исключение
- Все контекстные страницы, на которые имеются ссылки в текущей странице содержимого, должны иметь код подключения выбранного шаблона
- Для межстраничной передачи информации о выбранном шаблоне ее нужно где-то сохранять. Как и в случае с темами, это могут быть скрытые поля состояния вида (VIEWSTATE), глобальные объекты уровня сессии или приложения
Учитывая, что наши страницы Satellite.aspx, Satellite1.aspx, Satellite2.aspx, Satellite3.aspx согласованы с Title.master, сделаем их копии и настроим под динамическую смену мастер-страниц.
- В панели Solution Explorer создайте копию файла Title.master с именем Title1.master
- Откройте мастер-страницу Title1.master и добавьте выше объекта ImageBanner (после открывающего дескриптора <div> ) элемент ContentPlaceHolder с именем ContentPlaceHolderList
- Добавьте к гиперссылкам HyperLink еще одну с названием " Автошкола в целом "
- Сохраните и закройте файл Title1.master
- В панели Solution Explorer создайте копию файла Title1.master с именем Title2.master
- Сделайте копии файлов контекстных страниц Satellite?.aspx и присвойте им имена SatelliteDynamic.aspx, SatelliteDynamic1.aspx, SatelliteDynamic2.aspx, SatelliteDynamic3.aspx и SatelliteDynamic4.aspx соответственно
- Определите страницу SatelliteDynamic.aspx стартовой
-
Откройте
мастер-страницу Title2.master и
выполните в ней следующее:
- Полностью удалите контейнер скриптов <script runat="server">...</script>
- Удалите объект ImageBanner и внесите еще какие-нибудь визуально отличимые изменения
- Заполните свойство NavigateUrl гиперссылок адресами новых контекстных страниц, а ссылку " Автошкола в целом " адресуйте на SatelliteDynamic.aspx
- В панели Solution Explorer выделите сразу все контекстные страницы SatelliteDynamic?.aspx и откройте их в режиме Source, чтобы вручную заменить атрибут MasterPageFile="~/MasterPages/Title.master" на MasterPageFile="~/MasterPages/Title1.master"
- Откройте контекстную страницу SatelliteDynamic.aspx и в режиме Design создайте контейнер содержимого для шаблона ContentPlaceHolderList, выполнив на нем команду Create Custom Content контекстного меню
- Добавьте в контейнер контекста предваряющий текст " Выберите мастер-страницу:" и элемент DropDownList с именем lstMasterPages
- Заполните раскрывающийся список lstMasterPages так
Text | Value | |
---|---|---|
Items[0] | Мастер-страница с баннером | ~/MasterPages/Title1.master |
Items[1] | Мастер-страница без баннера | ~/MasterPages/Title2.master |
- Установите для списка lstMasterPages свойство AutoPostBack="True"
- В режиме Design двойным щелчком на тускло просвечивающемся заполнителе мастер-страницы создайте контейнер для скриптов, обработчик Page_Load() и переименуйте его в Page_Init()
- Скопируйте заготовку обработчика Page_Init() и переименуйте копию в Page_PreInit(), поскольку все они имеют одинаковую сигнатуру
- В режиме Design двойным щелчком на объекте lstMasterPages списка создайте обработчик изменения выбора опции с именем lstMasterPages_SelectedIndexChanged()
- Заполните обработчики, чтобы окончательный код страницы был таким
<%@ Page Language="C#" MasterPageFile="~/MasterPages/Title1.master" Title="Untitled Page" %> <script runat="server"> protected void Page_Init(object sender, EventArgs e) { if (Session["index"] != null) { // Восстанавливаем новое состояние списка lstMasterPages.SelectedIndex = (int)Session["index"]; } } protected void Page_PreInit(object sender, EventArgs e) { if (Session["Master"] != null) { // Был ранее сохраненный выбор, включить его Page.MasterPageFile = (string)Session["Master"]; } } protected void lstMasterPages_SelectedIndexChanged(object sender, EventArgs e) { // Запоминаем новый выбор пользователя Session["Master"] = lstMasterPages.SelectedValue; // Запоминаем новое состояние списка Session["index"] = lstMasterPages.SelectedIndex; // Обновляем страницу без полного цикла, // чтобы новая мастер-страница вступила в действие Server.Transfer(Request.FilePath); } </script> <asp:Content ID="Content1" runat="server" ContentPlaceHolderID="ContentPlaceHolderList"> Выберите мастер-страницу: <asp:DropDownList ID="lstMasterPages" runat="server" OnSelectedIndexChanged="lstMasterPages_SelectedIndexChanged" AutoPostBack="True"> <asp:ListItem Value="~/MasterPages/Title.master">Мастер-страница с баннером </asp:ListItem> <asp:ListItem Value="~/MasterPages/Title1.master">Мастер-страница без баннера </asp:ListItem> </asp:DropDownList> </asp:Content>Листинг 31.57. Окончательный код страницы SatelliteDynamic.aspx
- Откройте поочередно файлы SatelliteDynamic1.aspx, SatelliteDynamic2.aspx, SatelliteDynamic3.aspx , SatelliteDynamic4.aspx и добавьте в каждый из них после директивы @Page такой блок скриптов
<script runat="server"> protected void Page_PreInit(object sender, EventArgs e) { if (Session["Master"] != null) { // Был ранее сохраненный выбор, включить его Page.MasterPageFile = (string)Session["Master"]; } } </script>Листинг 31.58. Скрипты остальных контекстных страниц для загрузки выбранного шаблона
- Исполните начальную страницу SatelliteDynamic.aspx и убедитесь, что мы дали пользователю полнофункциональный механизм выбора шаблонов форматирования
Упражнение 17. Многослойное подключение мастер-страниц
Принципиально возможно подключение одной мастер-страницы к другой, система ASP.NET это позволяет. Можно использовать столько уровней вложения мастер-страниц, сколько это необходимо. Но нужно иметь ввиду, что многокаскадная схема подключения шаблонов делает код запутанным и ненадежным, поэтому рекомендуется использовать только один уровень мастер-страниц.
Но мы, все-таки, рассмотрим эту возможность на примере мастер-страниц двух уровней. Мы создадим две мастер-страницы с последовательным подключением нижнего уровня Level1 к верхнему Level0.
- Код страницы сделайте таким
<%@ Master 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 style="text-align: center; color: #0000ff"> <h1> Мастер-страница уровня Level1 - наибольшей глубины. Ее можно использовать как верхний колонтитул </h1> <asp:ContentPlaceHolder ID="ContentPlaceHolderLevel1" runat="server"> </asp:ContentPlaceHolder> </div> </form> </body> </html>Листинг 31.59. Дескрипторный код страницы MasterPageLevel1.master
- Теперь также в корне Web-дерева создайте мастер-страницу верхнего уровня с именем MasterPageLevel0.master и подключите к ней предыдущую через атрибут MasterPageFile директивы @Master
Код страницы должен выглядеть так
<%@ Master Language="C#" MasterPageFile="~/MasterPageLevel1.master" %> <asp:Content ID="ContentLevel0" ContentPlaceHolderID="ContentPlaceHolderLevel1" runat="server"> <table style="background-color: #ccff00" border="1"> <tr> <td colspan="2"> <h2> Мастер-страница уровня Level0 - верхнего уровня </h2> </td> </tr> <tr> <td style="width: 200px"> <strong>Здесь можно расположить элементы навигации</strong> </td> <td style="background-color: #ccffff"> <asp:ContentPlaceHolder ID="ContentPlaceHolderLevel0" runat="server"> </asp:ContentPlaceHolder> </td> </tr> </table> </asp:Content>Листинг 31.60. Дескрипторный код страницы MasterPageLevel0.master
Обратите внимание, что при попытке переключить созданную мастер-страницу в режим Design оболочка выдает предупреждение
Это значит, что автоматизированный графический режим Design работает только для мастер-страницы верхнего уровня, а для уровней мастер-страниц большей глубины дескрипторный код нужно будет писать вручную в режиме Source.
- Выполните для страницы MasterPageLevel0.master команду Website/Add Content Page, чтобы создать для нее контекстную страницу
- Измените имя по умолчанию Default.aspx созданной контекстной страницы на TestMasterPageLevel.aspx и отредактируйте ее так
<%@ Page Language="C#" MasterPageFile="~/MasterPageLevel0.master" Title="Untitled Page" %> <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolderLevel0" runat="Server"> <strong>Это есть заменяющее содержимое для мастер-страницы верхнего уровня Level0</strong> </asp:Content>Листинг 31.61. Дескрипторный код страницы TestMasterPageLevel.aspx
- Назначьте контекстную страницу TestMasterPageLevel.aspx стартовой и исполните ее
Результат будет таким
Итак, все работает, но нам это не надо - слишком запутано и посмотреть в Design нельзя!
Подключение мастер-страницы через конфигурационный файл
Для страниц, которые не имеют подключения мастер-страницы посредством атрибута MasterPageFile, можно задать мастер-страницу по умолчанию в кофигурационном файле блоком
<configuration> <system.web> <pages masterPageFile="XXX.master" /> </system.web> </configuration>
Этот подход не считается надежным, поскольку требует строгого согласования всех контекстных страниц с шаблонами одной мастер-страницы. Как только это условие будет нарушено, появится исключение. Если необходимо применить именно этот вариант, то нужно создать отдельную папку со своим файлом web.config и поместить в нее мастер-страницу и согласованные контекстные страницы.