Практикум прикладного программирования на C# в среде VS.NET 2005

Многокадровые элементы управления

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

Файлы к лабораторной работе Вы можете скачать здесь.

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

Упражнение 1. Элемент управления MultiView

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

  • Создайте новый пустой проект с именем MultiView, выполнив команду меню File/New/WebSite и определив параметры мастера так
  • Командой Add New Item добавьте к проекту страницу типа Web Form с отделенным кодом и именем MultiViewControl.aspx
  • Поместите на страницу в режиме редактора Design из вкладки Standard компонент-контейнер MultiView
  • Поместите на страницу в режиме редактора Design внутрь созданного объекта MultiView1 из той же вкладки Standard три экземпляра компонента View (компонент View называют представлением данных)
  • В результате оболочка сгенерирует следующий код разметки

    <%@ Page AutoEventWireup="true" 
           CodeFile="MultiViewControl.aspx.cs" 
         Inherits="MultiViewControl" 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:MultiView ID="MultiView1" runat="server">
                <asp:View ID="View1" runat="server">
                </asp:View>
                <asp:View ID="View2" runat="server">
                </asp:View>
                <asp:View ID="View3" runat="server">
                </asp:View>
            </asp:MultiView>
        </div>
        </form>
    </body>
    </html>
  • Запустите приложение и вы получите чистый экран броузера, поскольку созданные вкладки - представления еще не были заполнены интерфейсными элементами, поэтому они ничего и не генерируют для клиента
  • Замечание. Представления View можно добавлять и программно по мере необходимости (как и любой другой элемент управления). Для этого нужно создать экземпляр (например, View1 ) нового представления и добавить ссылку на него в коллекцию Views экземпляра (например, MultiView1 ) элемента MultiView с помощью MultiView1.Views.Add(View1) или MultiView1.Views.AddAt(index, View1). Свойство Views определено в классе System.Web.UI.WebControls.ViewCollection, который и имеет указанные методы Add() и AddAt(). Но мы будем для простоты использовать декларативный способ этапа проектирования.

    Web-форма в оболочке после наших действий будет иметь вид

    Какое представление будет генерировать элемент MultiView, зависит от значения свойства MultiView.ActiveViewIndex, доступного декларативно и программно. Если значение этого свойства равно " -1 ", то при исполнении страницы ни одна из вкладок не будет генерировать HTML-отклик. Если свойство установлено в ноль, то будет работать первая вкладка, и т.д.

    Продолжим выполнение упражнения и наполним представления View1, View2, View3 вариантами содержимого.

  • Командой Add Existing Item добавьте в корневую папку сайта какой-нибудь рисунок Web-формата (*. gif, *. jpg, *. png ), который занимает не очень много места. Один из вариантов рисунка - файл MyPhoto.jpg в прилагаемой папке Source
  • Поместите в представление View1 из вкладки Standard компонент Image (контейнер для рисунка) и через панель Properties декларативно настройте его так:
  • ImageUrl =" ~/MyPhoto.jpg " (символ ' ~ ' тильда обозначает корень виртуального каталога сайта)
  • Поместите в представление View2 какой-нибудь текст
  • Поместите в представление View3 элемент Calendar из вкладки Standard и настройте его внешний вид
  • Выделите объект MultiView1 и установите его свойство ActiveViewIndex в значение ноль, чтобы при начальной загрузке страницы было открыто первое представление
  • После выполненных действий разметка страницы будет описываться следующим кодом

    <%@ Page AutoEventWireup="true" 
        CodeFile="MultiViewControl.aspx.cs" 
        Inherits="MultiViewControl" Language="C#" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления множеством представлений</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                 <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
                    <asp:View ID="View1" runat="server">
                        <h1>Мое фото</h1>
                        <asp:Image ID="Image1" runat="server" ImageUrl="~/MyPhoto.jpg" />
                    </asp:View>
                    
                    <asp:View ID="View2" runat="server">
                        <h1>Мои стихи</h1>
                        <p>
                            У Лукоморья дуб зеленый<br />
                            Златая цепь на дубе том<br />
                            И днем и ночью кот ученый<br />
                            Все ходит по цепи кругом
                        </p>
                    </asp:View>
                    
                    <asp:View ID="View3" runat="server">
                        <h1>Мой календарь</h1>
                        <asp:Calendar ID="Calendar1" runat="server" BackColor="#C0FFFF" 
                            BorderColor="Red" BorderStyle="Ridge">
                        </asp:Calendar>
                    </asp:View>
                </asp:MultiView>
            </div>
        </form>
    </body>
    </html>

    Если сейчас запустить страницу MultiViewControl.aspx на выполнение, то мы увидим только первую раскрытую вкладку с фотографией, а для активизации других вкладок у нас нет пока механизма.

    Управление работой вкладок

    Вариант 1

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

  • Поместите на форму страницы впереди элемента MultiView1 компонент DropDownList из вкладки Standard
  • Установите для списка свойство AutoPostBack в значение True, чтобы при выборе нового пункта автоматически выполнялась обратная отсылка
  • После этих действий дескрипторный код страницы станет таким

    <%@ Page AutoEventWireup="true" 
        CodeFile="MultiViewControl.aspx.cs" 
        Inherits="MultiViewControl" Language="C#" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления множеством представлений</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" >
                </asp:DropDownList>
                <br />
                <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
                    <asp:View ID="View1" runat="server">
                        <h1>Мое фото</h1>
                        <asp:Image ID="Image1" runat="server" ImageUrl="~/MyPhoto.jpg" />
                    </asp:View>
                    
                    <asp:View ID="View2" runat="server">
                        <h1>Мои стихи</h1>
                        <p>
                            У Лукоморья дуб зеленый<br />
                            Златая цепь на дубе том<br />
                            И днем и ночью кот ученый<br />
                            Все ходит по цепи кругом
                        </p>
                    </asp:View>
                    
                    <asp:View ID="View3" runat="server">
                        <h1>Мой календарь</h1>
                        <asp:Calendar ID="Calendar1" runat="server" BackColor="#C0FFFF" 
                            BorderColor="Red" BorderStyle="Ridge">
                        </asp:Calendar>
                    </asp:View>
                </asp:MultiView>
            </div>
        </form>
    </body>
    </html>
  • Выделите экземпляр DropDownList1 и через панель Properties в режиме Events создайте в застраничном файле MultiViewControl.aspx.cs обработчик события SelectedIndexChanged, который заполните так
  • // Обработчик события выбора в списке
        protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
        {
            MultiView1.ActiveViewIndex = DropDownList1.SelectedIndex;
        }
  • Поместите в обработчик события Load застраничного файла MultiViewControl.aspx.cs следующий код
  • protected void Page_Load(object sender, EventArgs e)
        {
            // Заполняем список только при первом запросе страницы,
            // а потом все будет сохраняться в состоянии вида.
            // Иначе список всегда будет переустанавливаться в начало
            if (!IsPostBack)
            {
                // Подсоединяем коллекцию с вкладками к списку
                DropDownList1.DataSource = MultiView1.Views;
                // Назначаем атрибут, значениями которого
                // будут заполнены поля "Text" списка
                DropDownList1.DataTextField = "ID";
                // Заполняем список подсоединенными данными
                DropDownList1.DataBind();
        
                // Отображаем первое представление
                MultiView1.ActiveViewIndex = 0;
                // Синхронизируем список
                DropDownList1.SelectedIndex = 0;
        
                // Выделяем текущую дату 
                Calendar1.SelectedDate = DateTime.Now.Date;
                Calendar1.SelectedDayStyle.BorderStyle = BorderStyle.Solid;
            }
        }
  • Выполните страницу, результат должен быть не менее лучезарным, чем этот...
  • Вариант 2

    В обработчике события Page_Load() мы, для тренировки, вставили код, чтобы при первом запросе страницы список программно заполнялся значениями атрибутов ID представлений. Этого можно и не делать, если вручную на этапе проектирования заполнить свойство Items списка более осмысленными именами.

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

  • Через панель Solution Explorer выполните копию страницы MultiViewControl.aspx и присвойте копии новое имя MultiViewControl1.aspx.
  • Обратите внимание, что файл кода .cs автоматически копируется и переименовывается вместе со страницей. Более того, в оболочке даже не предусмотрена возможность переименовать его отдельно, пока он связан со страницей. Если же его скопировать отдельно, тогда он переименовывается.

  • Выполните команду меню Window/Close All Documents, чтобы закрыть все прежние окна редактирования рабочей области оболочки
  • Откройте новую страницу MultiViewControl1.aspx на редактирование и выполните команду меню Website/Set As Start Page, чтобы сделать ее стартовой при запуске из оболочки
  • Выделите список через панель Properties и сбросьте его свойство AutoPostBack в False
  • Через раскрывающийся список в верхней части панели Properties выделите объект MultiView1 и задайте ActiveViewIndex = -1, чтобы ни одно представление при первой загрузке страницы у пользователя не было раскрыто
  • В файле MultiViewControl1.aspx.cs полностью очистите обработчик события Page_Load(), код которого в предыдущем примере программно заполнял список (можно полностью удалить этот обработчик, нам он здесь не понадобится)
  • Сейчас мы должны заполнить список выбора вкладок декларативно (на этапе проектирования).

  • Выделите список и заполните его свойство Items так
  • Декларативные настройки объекта DropDownList1
    Items[i] Text Value
    Items[0] Моя фотография не имеет значения ...
    Items[1] Мои стихи не имеет значения ...
    Items[2] Встроенный календарь не имеет значения ...
  • Добавьте на новую страницу справа от списка кнопку Input (Submit) из вкладки HTML панели Toolbox (воспользуемся простой кнопкой) и задайте ей следующие настройки:
  • ID = Submit1
  • Value = Show
  • Title = Раскрыть вкладку
  • Запустите приложение и понажимайте кнопку Show, не изменяя список
  • Ничего не происходит, пока в списке мы не выбирем новый пункт. Только после этого свойство MultiView1. ActiveViewIndex примет отличное от -1 значение и представления при обратной отсылке начнут работать. Чтобы исправить это, нужно код присвоения значения свойству ActiveViewIndex переместить из обработчика спискового события SelectedIndexChanged в обработчик щелчка кнопки.

  • Создайте обработчик события Click для кнопки Submit1 двойным щелчком на ней мышью
  • Мы видим, что оболочка создала код заготовки JavaScript -сценария, который мы должны заполнить и который страница готова посылать на клиентский броузер. Это стандартное поведение оболочки при создании обработчиков: если элемент управления на активной странице не помечен как серверный (нет атрибута runat =" server "), значит свою динамику он может реализовать только на стороне клиента в блоке сценариев JavaScript.

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

  • Откатите состояние редактора до шага, предшествующего созданию обработчика, или же выполните следующие действия по очистке кода:
  • Удалите созданный оболочкой предыдущим действием код JavaScript -сценария. Для этого в режиме Source поместите текстовый курсор редактора внутрь блока кода <script language="javascript" type="text/javascript">..|..</script> и в нижней части рамки окна редактора щелкните на кнопке <script>. Весь выделенный код можно удалять
  • Удалите из дескриптора <input> кнопки Submit1 код регистрации обработчика onclick="return Submit1_onclick()", сгенерированный оболочкой
  • Щелкните на Submit1 правой кнопкой мыши и выполните команду Run As Server Control. Этим действием в дескриптор <input> будет добавлен атрибут runat="server", который заставит ASP.NET запускать обработчик кнопки (если мы его предусмотрим), если с броузера с обратной отсылкой будет прислано событие, что клиент щелкал на этой кнопке
  • Выделите список DropDownList1 и через панель Properties в режиме Events очистите поле события SelectedIndexChanged, тем самым оболочка удалит из дескриптора DropDownList1 ссылку на этот обработчик. После этого обработчик станет свободным методом класса, у которого нет неявных вызовов с помощью механизма событий
  • Двойным щелчком на кнопке Submit1, теперь уже серверной, создайте для нее обработчик в файле MultiViewControl1.aspx.cs
  • Перенесите код обработчика события SelectedIndexChanged в код нового обработчика, а старый обработчик события SelectedIndexChanged удалите
  • В результате код файла будет таким

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
      
    public partial class MultiViewControl : System.Web.UI.Page 
    {
        // Обработчик события на кнопке Submit1
        protected void Submit1_ServerClick(object sender, EventArgs e)
        {
            MultiView1.ActiveViewIndex = DropDownList1.SelectedIndex;
        }
    }
  • Выполните страницу и отметьте следующее
  • При первой загрузке страницы обработчик щелчка на кнопке еще не сработал, поскольку не было обратной отсылки, а выполнился только отклик на первый запрос. Но все последующие обратные отсылки страницы выполняются по щелчку клиента на кнопке Submit1 и присылают на сервер информацию о том, что на клиенте произошло событие Click. По прибытию на сервер такой обратной отсылки система ASP.NET распознает присланное событие Click, свойству MultiView1.ActiveViewIndex в обработчике присваивается значение выбранной пользователем опции списка и элемент MultiView1 при формировании текущего отклика генерирует содержимое вкладки, соответствующей этому выбору.

    Добавление к MultiView функций навигации

    На предыдущих шагах мы знакомились с механизмом работы элемента MultiView. Мы использовали для смены вкладок внешний по отношению к MultiView элемент списка DropDownList1. Но MultiView имеет собственные средства для перехода по своим вкладками. Эти возможности основаны на том факте, что серверные элементы Button, ImageButton, LinkButton реализуют интерфейс System.Web.UI.WebControls. IButtonControl, от которого наследуют способность генерировать и распознавать не только событие Click, но и событие Command. Такие элементы управления называются кнопочными. Они реализуют ряд полезных свойств интерфейса, таких как CommandArgument, CommandName и др.

    В свою очередь, элемент управления MultiView содержит общедоступные переменные (поля), которые ожидают поступления определенных команд, чтобы MultiView соответствующим образом их исполнил

    Вот какие значения своих полей ожидает элемент MultiView

    Имена команд, которые может распознать MultiView
    Поле элемента MultiView Ждет команду Описание действия MultiView
    NextViewCommandName NextView Переход к следующему представлению. Команда является значением свойства CommandName кнопочного элемента
    PreviousViewCommandName PrevView Переход к предыдущему представлению. Команда является значением свойства CommandName кнопочного элемента
    SwitchViewByIDCommandName SwitchViewByID Переход к представлению со значением идентификатора ID, переданным из свойства CommandArgument кнопочного элемента управления
    SwitchViewByIndexCommandName SwitchViewByIndex Переход к представлению с определенным индексом, переданным из свойства CommandArgument кнопочного элемента управления

    Добавим в нашу страницу описанную возможность навигации по вкладкам элемента MultiView.

  • В панели Solution Explorer скопируйте страницу MultiViewControl1.aspx, присвойте копии имя MultiViewControl2.aspx и сделайте эту страницу стартовой
  • Из вкладки Standard панели Toolbox поместите в нижнюю часть первой View1 и последней View3 вкладки по одной серверной кнопке Button, а в нижнюю часть средней вкладки View2 - две кнопки
  • Отклик для средней вкладки после размещения в нижней ее части двух кнопок будет таким

  • Настройте кнопки как показано в таблице
  • Настройка кнопок навигации на вкладках
    Вкладка Свойство кнопки Значение
    View1 ID btnNext0
    Text Next >
    CommandName NextView
    View2 ID btnPrev1
    Text < Prev
    CommandName PrevView
    ID btnNext1
    Text Next >
    CommandName NextView
    View3 ID btnPrev2
    Text < Prev
    CommandName PrevView

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

  • Установите редактор страницы в режим Design
  • В панели Properties в верхнем раскрывающемся списке выберите объект MultiView1, переведите панель в режим Events (кнопка с пиктограммой молнии) и двойным щелчком на поле события ActiveViewChanged создайте обработчик, который заполните кодом синхронизации списка
  • В результате файл поддержки страницы должен быть таким

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
      
    public partial class MultiViewControl : System.Web.UI.Page 
    {
        // Обработчик события на кнопке Submit1
        // Синхронизация представлений со списком
        protected void Submit1_ServerClick(object sender, EventArgs e)
        {
            MultiView1.ActiveViewIndex = DropDownList1.SelectedIndex;
        }
      
        // Синхронизация списка с представлениями
        protected void MultiView1_ActiveViewChanged(object sender, EventArgs e)
        {
            DropDownList1.SelectedIndex = MultiView1.ActiveViewIndex;
        }
    }

    Файл дескрипторного представления будет таким

    <%@ Page AutoEventWireup="true" 
        CodeFile="MultiViewControl2.aspx.cs" 
        Inherits="MultiViewControl" Language="C#" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления множеством представлений</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:DropDownList ID="DropDownList1" runat="server">
                    <asp:ListItem>Моя фотография</asp:ListItem>
                    <asp:ListItem>Мои стихи </asp:ListItem>
                    <asp:ListItem>Встроенный календарь</asp:ListItem>
                </asp:DropDownList>
                
                <input id="Submit1" type="submit" value="Show" 
                    title="Раскрыть вкладку" runat="server" 
                    onserverclick="Submit1_ServerClick" /><br />
                    
                <asp:MultiView ID="MultiView1" runat="server" 
                    OnActiveViewChanged="MultiView1_ActiveViewChanged">
                    <asp:View ID="View1" runat="server">
                        <h1>
                            Мое фото</h1>
                        <asp:Image ID="Image1" runat="server" 
                            ImageUrl="~/MyPhoto.jpg" /><br />
                        <br />
                        <asp:Button ID="btnNext0" runat="server" 
                            CommandName="NextView" Text="Next >" />
                    </asp:View>
                    
                    <asp:View ID="View2" runat="server">
                        <h1>
                            Мои стихи</h1>
                        <p>
                            У Лукоморья дуб зеленый<br />
                            Златая цепь на дубе том<br />
                            И днем и ночью кот ученый<br />
                            Все ходит по цепи кругом
                        </p>
                        <asp:Button ID="btnPrev1" runat="server" 
                            CommandName="PrevView" Text="< Prev" />
                        <asp:Button ID="btnNext1" runat="server" 
                            CommandName="NextView" Text="Next >" />
                    </asp:View>
                    
                    <asp:View ID="View3" runat="server">
                        <h1>
                            Мой календарь</h1>
                        <asp:Calendar ID="Calendar1" runat="server" 
                            BackColor="#C0FFFF" BorderColor="Red"
                            BorderStyle="Ridge" />
                        <br />
                        <asp:Button ID="btnPrev2" runat="server" 
                            CommandName="PrevView" Text="< Prev" />
                    </asp:View>
                </asp:MultiView>
            </div>
        </form>
    </body>
    </html>
  • Выполните страницу и убедитесь, что все работает как нужно
  • Хороший элемент, что и говорить. Но есть один существенный недостаток. Поскольку хранится несколько представлений, то мы должны быть готовы вернуться к любому представлению, если его повторно вызовет пользователь. Это значит, что мы должны сохранять состояние вида всех представлений, в том числе и невидимых в данный момент. Из-за этого элемент посылает на клиентскую машину большой объем кода состояния вида. От этой неприятности можно избавиться, отключив свойство EnableViewState, но тогда последние пользовательские настройки вкладок текущего сеанса сохраняться не будут.

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

    Упражнение 2. Элемент управления Wizard

    Элемент управления Wizard (мастер) является более развитым, чем элемент MultiView. Он имеет богатую настраиваемую функциональность, включающую в себя

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

  • Добавьте к проекту MultiView новую страницу с именем WizardControl.aspx и файлом отделенного кода. Назначьте ее стартовой
  • В режиме Design редактора поместите на страницу элемент управления Wizard из вкладки Standard панели Toolbox
  • Будет сгенерирована такая заготовка

    Разметка страницы на данном этапе будет представлена следующим кодом

    <%@ Page Language="C#" AutoEventWireup="true" 
        CodeFile="WizardControl.aspx.cs" Inherits="WizardControl" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления Wizard</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Wizard ID="Wizard1" runat="server" ActiveStepIndex="0">
                    <WizardSteps>
                        <asp:WizardStep runat="server" Title="Step 1">
                        </asp:WizardStep>
                        <asp:WizardStep runat="server" Title="Step 2">
                        </asp:WizardStep>
                    </WizardSteps>
                </asp:Wizard>
            </div>
        </form>
    </body>
    </html>

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

    В элементе управления MultiView все представления на этапе проектирования раскрыты для разработчика. Для элемента Wizard оболочка Visual Studio 2005 показывает разработчику вкладку только одного текущего шага.

    Чтобы создать новые шаги мастера, нужно:

  • просто добавлять в его контейнер дескрипторы <asp:WizardStep>
  • или через локальную панель задач выполнить опцию Add/Remove WizardSteps
  • или в панели Properties вызвать на редактирование свойство WizardSteps
  • Обратите внимание, что по умолчанию дескрипторы <asp:WizardStep> шагов -вкладок не имеют значения идентификатора ID. Здесь подразумевается, что для такого сложного элемента управления разработчику достаточно декларативной настройки. Если же в дальнейшем разработчик предполагает программно управлять шагами мастера, то он должен прописать атрибуты ID в дескрипторах шагов.

    В приведенном окне редактирования коллекции шагов -вкладок наиболее существенными являются следующие свойства дескриптора <asp:WizardStep>

    Некоторые свойства дескриптора <asp:WizardStep>
    Свойство Описание
    Title Имя шага, видимое пользователю в ссылках на боковой панели слева
    StepType

    Это свойство определяет тип кнопок навигации, которые будут предъявлены пользователю данным шагом, и равно одному из значений перечисления System.Web.UI.WebControls.WizardStepType.WizardStepType:

  • Auto - определяется по умолчанию и устанавливает тип кнопки в зависимости от местонахождения шага в коллекции. Если шаг стоит на первом месте, то будет кнопка Start, во всех промежуточных позициях - кнопка Step, если на последнем месте - будет кнопка Finish
  • Complete - не показывает никаких кнопок и скрывает боковую панель
  • Finish - показывает кнопки Finish и Previous
  • Start - показывает кнопку Next
  • Step - показывает кнопки Next и Previous
  • AllowReturn Показывает, может ли пользователь возвращаться к этому шагу после того, как его пройдет. Если это свойство имеет значение false, то как только пользователь пройдет этот шаг, он не сможет вернуться назад. Потому что все ссылки, ведущие к этому пройденному шагу, немедленно будут блокированы.

    Наполним шаги мастера конкретным содержимым - элементами управления, и настроим их свойства. Всего создадим четыре шага, в которых разместим:

  • WizardStep1 - раскрывающийся список DropDownList
  • WizardStep2 - список радиокнопок RadioButtonList
  • WizardStep3 - текстовое поле TextBox
  • WizardStep4 - обычный текст
  • Оболочка Visual Studio 2005 все отличные от значений по умолчанию свойства элементов сохраняет в дескрипторах текстового файла .aspx как дополнительные атрибуты. Более того, при установке значений отдельным свойствам оболочка сама генерирует новые дескрипторы и даже целые блоки кода. Поэтому все декларативные настройки сложных элементов управления нужно выполнять через панель Properties, но для краткости изложения приведем уже готовый код настройки страницы нашего примера.

    <%@ Page Language="C#" AutoEventWireup="true" 
        CodeFile="WizardControl.aspx.cs" Inherits="WizardControl" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления Wizard</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Wizard ID="Wizard1" runat="server" BackColor="#EFF3FB" 
                    BorderColor="#B5C7DE"
                    BorderWidth="1px" ActiveStepIndex="0" 
                    StartNextButtonText="Далее >"
                    StepNextButtonText="Далее >" StepPreviousButtonText="< Назад" 
                    FinishCompleteButtonText="Готово" FinishPreviousButtonText="< Назад" 
                    HeaderText="Жизненно важная анкета!">
                    <WizardSteps>
                        <asp:WizardStep ID="WizardStep1" runat="server" Title="Друзья">
                            <h3>
                                Какой президент самый лучший?</h3>
                            <asp:DropDownList ID="DropDownList1" runat="server">
                                <asp:ListItem>Наш Медведев</asp:ListItem>
                                <asp:ListItem>Их Обама</asp:ListItem>
                                <asp:ListItem>Похожий на Чингиз-Хана</asp:ListItem>
                                <asp:ListItem>Вы сами</asp:ListItem>
                                <asp:ListItem>Ваша соседка</asp:ListItem>
                            </asp:DropDownList>
                        </asp:WizardStep>
                        <asp:WizardStep ID="WizardStep2" runat="server" Title="Туризм">
                            <h2>
                                Где Вы были с 19 по 21 августа 1991 года?</h2>
                            <asp:RadioButtonList ID="RadioButtonList1" runat="server">
                                <asp:ListItem>На Красной площади</asp:ListItem>
                                <asp:ListItem>На Луне</asp:ListItem>
                                <asp:ListItem>В чужом огороде</asp:ListItem>
                                <asp:ListItem>У тетеньки</asp:ListItem>
                                <asp:ListItem>В ауте</asp:ListItem>
                            </asp:RadioButtonList>
                        </asp:WizardStep>
                        <asp:WizardStep ID="WizardStep3" runat="server" Title="Встречи">
                            <h3>
                                Кайтесь! Место встречи изменить нельзя!</h3>
                            Ваш ИНН:
                            <asp:TextBox ID="TextBox1" runat="server" />
                        </asp:WizardStep>
                        <asp:WizardStep ID="WizardStep4" runat="server" Title="Досуг">
                            <h2>
                                Мера поощрения</h2>
                            Усиленная диета + клизьма с перцем!
                        </asp:WizardStep>
                    </WizardSteps>
                    <HeaderStyle BackColor="Blue" Font-Bold="True" Font-Size="X-Large" ForeColor="Yellow" />
                </asp:Wizard>
            </div>
        </form>
    </body>
    </html>

    Несколько замечаний:

  • Боковую панель навигационных ссылок можно отключать свойством Wizard.DisplaySideBar =" False "
  • Оболочка в режиме проектирования автоматически изменяет значение свойства Wizard.ActiveStepIndex при редактировании текущего шага. Поэтому, чтобы страница при запуске показала первый шаг, небходимо в конце редактирования либо на него перейти, либо установить Wizard.ActiveStepIndex ="0"
  • Мы еще ничего не программировали, а уже успели добиться такой мощной функциональности страницы
  • Последний дескриптор кода <HeaderStyle> определяет стиль заголовочного блока элемента Wizard
  • Запустите страницу с настроенным элементом Wizard и "подывитесь", какой же все-таки Большой Билл умный, да еще так вовремя - какие масштабы и горизонты открывают для нас эти его инструменты (ну, прямо, Эльдорадо!)
  • Программирование событий элемента управления Wizard

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

    События, поддерживаемые элементом Wizard
    Событие О чем информирует пришедшее от клиента событие
    ActiveStepChanged Пользователь переключился на новый шаг или код внутри страницы изменил свойство ActiveStepIndex
    CancelButtonClick Пользователь щелкнул на кнопке Cancel (Отмена). Кнопка Cancel по умолчанию не отображается, однако ее можно добавить во все представления Step сразу, если установить свойство Wizard.DisplayCancelButton="True". Кнопка Cancel инициирует обратную отсылку, и если не предусмотреть соответствующего обработчика, то ничего не происходит. Но если одновременно определено свойство Wizard.CancelDestinationPageUrl, например, CancelDestinationPageUrl="~/Alternate.aspx", то по щелчку пользователя на этой кнопке ему отправляется другая страница
    FinishButtonClick Пользователь дошел до последнего шага и щелкнул на кнопке Finish
    NextButtonClick, PreviousButtonClick Эти события возникают при щелчке на кнопке Next или Previous на любом шаге. Но сменить шаг пользователь может и через боковую панель. Чтобы такой момент не упустить и однозначно среагировать на смену шага, лучше вместо этих событий обрабатывать событие ActiveStepChanged
    SideBarButtonClick Пользователь щелкнул на ссылке в области боковой панели
    Чувствуете?!!! Мы сидим со своим кодом на другом конце провода (на сервере) и ждем очередных пожеланий ненасытного пользователя. При получении от него очередного запроса мы анализируем выбор по присланным событиям и пакуем для него новую посылку, в которую закладываем и требуемый текущий ответ, и интерфейсные элементы для ввода новых пожеланий. Да все это еще должно быть красивым, блестящим и пушистым. Вот Большой Билл нам здесь и помогает - осталось только руки приложить.

    Используем событие FinishButtonClick, чтобы усовершенствовать наш пример. Когда пользователь щелкнет в последнем шаге -вкладке на кнопке Finish (Готово), соберем его выбор с каждого шага и вернем в раскрытом представлении этого последнего шага.

  • Откройте страницу WizardControl.aspx в режиме Design и перейдите на последний шаг WizardStep4 для его редактирования
  • Поместите в середину области шага текстовую метку Label из вкладки Standard панели Toolbox, присвойте ей имя lblSummary и очистите ее свойство Text
  • Выделите объект Wizard1 и через панель свойств в режиме Events создайте обработчик для события FinishButtonClick
  • Заполните обработчик следующим кодом
  • protected void Wizard1_FinishButtonClick(object sender, WizardNavigationEventArgs e)
        {
            // Библиотека Framework 2.0 в нашем распоряжении
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append("<h3>");
            sb.Append("Вы выбрали: <br />");
            string title;
      
            title = WizardStep1.Title;
            sb.Append(title + ": " + DropDownList1.Text + "<br />");
      
            title = WizardStep2.Title;
            int index = RadioButtonList1.SelectedIndex;
            if(index != -1) // Если что-то выбрал
                sb.Append(title + ": " + RadioButtonList1.Items[index].Text + "<br />");
      
            /*  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
            // Для элемента класса CheckBoxList нужно проверять коллекцию:
            CheckBoxList CheckBoxList1;
            foreach (ListItem item in CheckBoxList1.Items)
            {
                if (item.Selected)
                    sb.Append(item.Text + "; ");
            }
                !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
      
            title = WizardStep3.Title;
            if (TextBox1.Text.Length > 0)// Если что-то ввел
                sb.Append(title + ": " + TextBox1.Text + "<br /></br />");
      
            sb.Append("</h3>");
      
            sb.Append("Вам рекомендуется:");
      
            // Отображаем собранные данные
            lblSummary.Text = sb.ToString();
        }

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

  • Перейдите в режиме Design на первый шаг WizardStep1, чтобы автоматически установилось в ноль значение свойства ActiveStepIndex объекта Wizard1 и пользователю вначале отображался первый шаг
  • Выполните страницу, заполните анкету и на последнем шаге щелкните на кнопке Готово
  • Обработчик отобразит пользователю примерно такой результат

    Стили элемента Wizard

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

    Например, для кнопки StartNext применяются следующие свойства:

    Некоторые свойства для настройки кнопок
    Свойство Описание
    StartNextButtonImageUrl Задает изображение для изображения-кнопки
    StartNextButtonStyle Использует стили внешней каскадной таблицы стилей CSS
    StartNextButtonText Настраивает текст кнопки или ссылки
    StartNextButtonType Определяет кнопку, ссылку или выбираемое изображение-кнопку

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

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

    Свойства Wizard, определяющие стили его элементов
    Стиль Описание
    ControlStyle Наследуется Wizard от класса WebControl и применяется ко всем его разделам
    HeaderStyle Применяется к разделу верхнего колонтитула, который будет отображаться только в том случае, если будет задан какой-нибудь текст в свойстве Wizard.HeaderText
    SideBarStyle Применяется к области боковой панели с кнопками
    SideBarButtonStyle Определяет стиль кнопок боковой панели
    StepStyle Применяется к компонентам представления, включенным в текущий шаг
    NavigationStyle Применяется к нижней области шагов, в которых расположены навигационные кнопки
    NavigationButtonStyle Применяется только к кнопкам навигации в области навигации
    StartNextButtonStyle Применяется к кнопке Next в первом шаге, если ее видимость задана свойством StepType=Start
    StepNextButtonStyle Применяется к кнопке Next в промежуточных шагах, если ее видимость задана свойством StepType=Step
    StepPreviousButtonStyle Применяется к кнопке Previous в промежуточных и последнем шагах, если ее видимость задана свойством StepType=Step
    FinishPreviousButtonStyle Применяется к кнопкам Finish и Previous в последнем шаге, если их видимость задана свойством StepType=Finish
    CancelButtonStyle Применяется к кнопке Cancel во всех шагах, если ее видимость задана свойством DisplayCancelButton=True

    Оболочка Visual Studio 2005 позволяет существенно облегчить жизнь разработчика наличием средств автоматизации по настройке типовых стилей, которых в большинстве случаев будет достаточно. Как и при настройке других сложных элементов управления (например, TreeView, Menu ), воспользуемся локальной панелью задач элемента Wizard, чтобы одним махом присвоить профессиональный стиль нашей странице.

  • Откройте страницу WizardControl.aspx в режиме Design и выделите объект Wizard1
  • Откройте локальную панель задач объекта Wizard1, щелкнув на пиктограмме треугольника в его правом верхнем углу
  • Выполните опцию Auto Format и в появившемся диалоговом окне выберите подходящий стиль
  • Окно Auto Format можно вызвать и через контекстное меню элемента Wizard, выполнив одноименную опцию

  • Выполните страницу WizardControl.aspx и убедитесь, что она приобрела профессиональный дизайн
  • Проанализируйте дескрипторное представление страницы, чтобы выяснить, какие свойства дескрипторов стилей позволили добавить такую красоту (у меня бы такое никогда вручную не получилось!!!)
  • Такое волшебство совершили несколько строчек кода, вот они

    <HeaderStyle BackColor="#FFCC66" Font-Bold="True" Font-Size="0.9em" ForeColor="#333333" 
        BorderColor="#FFFBD6" BorderStyle="Solid" BorderWidth="2px" HorizontalAlign="Center" />
    <SideBarStyle BackColor="#990000" Font-Size="0.9em" VerticalAlign="Top" />
    <NavigationButtonStyle BackColor="White" BorderColor="#CC9966" BorderStyle="Solid"
        BorderWidth="1px" Font-Names="Verdana" Font-Size="0.8em" ForeColor="#990000" />
    <SideBarButtonStyle ForeColor="White" />

    В приведенном коде каждый дескриптор настраивает свою область элемента Wizard. Обратите внимание, что приведенный блок кода настройки стилей оболочка добавляет в самый конец контейнера <asp:Wizard></asp:Wizard>, чтобы легче было искать. Если этот блок кода удалить, то мы вернемся к почти прежнему варианту стилей по умолчанию ( почти, потому, что может потребоваться корректировка атрибутов еще в некоторых других местах, например, в дескрипторе <asp:Wizard> - посмотрите сами!).

  • Налюбовавшись сей красотой, вызовите контекстное меню для элемента Wizard и выполните команду Auto Format/Remove Formating, чтобы вернуться на грешную Землю к стилям по умолчанию
  • Шаблоны элемента Wizard

    Если с помощью свойств-стилей нам не удается добиться желаемого эффекта, то можно воспользоваться свойствами-шаблонами. Ниже приведен полный список шаблонов элемента управления Wizard, выбранный как свойства из панели Object Browser

    Шаблоны элемента управления Wizard
    Шаблон или дескриптор Описание
    HeaderTemplate Определяет содержимое области верхнего колонтитула
    SideBarTemplate Определяет боковую панель, которая обычно включает ссылки навигации для каждого шага
    StartNavigationTemplate Определяет кнопку навигации для первого шага, если ее видимость задана свойством StepType=Start
    StepNavigationTemplate Определяет кнопки навигации в промежуточных и последнем шагах, если их видимость задана свойством StepType=Step
    FinishNavigationTemplate Определяет кнопку навигации Finish для последнего шага, если ее видимость задана свойством StepType=Finish

    Формирование шаблона <HeaderTemplate>

    Дескрипторный блок первого шаблона добавляется опцией Edit Templates через локальную панель задач, либо опцией Edit Template через контекстное меню элемента Wizard (одна и та же команда в разных местах по разному называется - Большой Билл тоже человек!).

  • В режиме Design выполните команду Edit Template/Header Template контекстного меню для элемента управления Wizard страницы WizardControl.aspx
  • В появившемся окне введите текст верхнего колонтитула " Это заголовок шага:" (или любую другую Абру-Кадабру, лишь-бы заготовка шаблона создалась, - все равно потом руками редактировать), после чего щелкните на опции End Template Editing локальной панели задач, чтобы завершить создание шаблона заголовка и вернуться в редактор Design
  • Если ничего в поле текста не ввести, то после выхода по опции End Template Editing дескриптор <HeaderTemplate> создан не будет.

  • Перейдите на странице в режим Source, найдите в конце блока кода созданный оболочкой дескриптор <HeaderTemplate> и отредактируйте его так
  • <HeaderTemplate>
        <h2>
            Это заголовок шага:                        
             <%= Wizard1.ActiveStep.Title %> 
        </h2>
    </HeaderTemplate>

    Получается, что мы шаблон заголовка должны заполнять вручную как обычный HTML-текст. Эта возможность оставлена в силу ее простоты (" Уж HTML-то они должны знать!", опрометчиво подумал Большой Билл). И для тренировки мы сами вставили в этот HTML-код операторный внедренный исполнимый блок <%=  имя_переменной_или_выражение  %>. Это обычный прием, применяемый, например, в PHP. При исполнении страницы вместо этого блока в статический текст будет подставлено значение указанной переменной или выражения. Таких блоков в статическом HTML-коде страницы мы можем наставить, сколько угодно. В нашем примере в указанном месте будет подставляться значение атрибута Title текущего шага, которые мы декларативно определили ранее при формировании шагов элемента Wizard.

  • Исполните страницу и вы увидите работу шаблона заголовка в действии
  • Обратите внимание, что хоть ранее мы и задали в панели Properties значение заголовка в свойстве HeaderText="Жизненно важная анкета!" элемента Wizard (этот атрибут и сейчас там присутствует). Эта настройка так и пройдет на страницу отклика, если ее не переопределить в шаблоне. Но как только мы добавили дескриптор шаблона заголовка, оболочка сразу же скрыла это свойство в панели Properties. Отображаться теперь будет именно заголовок шаблона.

    Формирование остальных шаблонов

    Все оставшиеся шаблоны областей элемента Wizard удобней создавать средствами оболочки в силу их сложности. Чтобы создать требуемый дескриптор шаблона, нужно выполнить соответствующую команду Conver to... (в контекстном меню элемента Wizard или его локальной панели). После этого можно приступать к редактированию созданного шаблона, выполнив опцию Edit Template.

    Команда Edit Template вызывает окно редактора шаблонов, в рабочей области которого находится прямоугольный индикатор настройки со своей локальной панелью. Стоит только выделить этот индикатор, сразу в панели Properties появляются доступные для настройки шаблона свойства.

    Завершение редактирования осуществляется командой End Template Editing контекстного меню или локальной панели

    Обратите внимание, что как только какой-то из шаблонов создан, то в меню соответствующая команда меняется с Conver to..., на Reset... Выполнение команды Reset... начисто удаляет дескрипторы соответствующего шаблона. Дескрипторы любого шаблона можно удалить и вручную в режиме Source, но для шаблона заголовка это можно сделать только вручную.

  • Добавьте к элементу Wizard шаблон <SideBarTemplate> и через панель Properties задайте ему свойство ItemStyle/BorderStyle="Outset"
  • Вернитесь в режим Design и убедитесь, что кнопки боковой панели стали выпуклые
  • Выполните страницу, все должно работать
  • Следует всегда помнить, что при всем многообразии настроек стилей и шаблонов интерфейс по умолчанию является самым вывереным с точки зрения экономии ресурсов при обмене с клиентом. Поэтому менять настройки нужно разумно, за неординарный интерфейс потребуется дополнительная плата, к тому же он может стать объектом насмешек искушенных гурманов.

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

  • Удалите шаблон <SideBarTemplate>, выполнив в режиме Design команду Reset SideBarTemplat контекстного меню элемента Wizard, и выберите красивый стандартный стиль Classic через опцию Auto Format того же меню
  • Страницы:

    Файлы к лабораторной работе Вы можете скачать здесь.

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

    Упражнение 1. Элемент управления MultiView

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

  • Создайте новый пустой проект с именем MultiView, выполнив команду меню File/New/WebSite и определив параметры мастера так
  • Командой Add New Item добавьте к проекту страницу типа Web Form с отделенным кодом и именем MultiViewControl.aspx
  • Поместите на страницу в режиме редактора Design из вкладки Standard компонент-контейнер MultiView
  • Поместите на страницу в режиме редактора Design внутрь созданного объекта MultiView1 из той же вкладки Standard три экземпляра компонента View (компонент View называют представлением данных)
  • В результате оболочка сгенерирует следующий код разметки

    <%@ Page AutoEventWireup="true" 
           CodeFile="MultiViewControl.aspx.cs" 
         Inherits="MultiViewControl" 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:MultiView ID="MultiView1" runat="server">
                <asp:View ID="View1" runat="server">
                </asp:View>
                <asp:View ID="View2" runat="server">
                </asp:View>
                <asp:View ID="View3" runat="server">
                </asp:View>
            </asp:MultiView>
        </div>
        </form>
    </body>
    </html>
  • Запустите приложение и вы получите чистый экран броузера, поскольку созданные вкладки - представления еще не были заполнены интерфейсными элементами, поэтому они ничего и не генерируют для клиента
  • Замечание. Представления View можно добавлять и программно по мере необходимости (как и любой другой элемент управления). Для этого нужно создать экземпляр (например, View1 ) нового представления и добавить ссылку на него в коллекцию Views экземпляра (например, MultiView1 ) элемента MultiView с помощью MultiView1.Views.Add(View1) или MultiView1.Views.AddAt(index, View1). Свойство Views определено в классе System.Web.UI.WebControls.ViewCollection, который и имеет указанные методы Add() и AddAt(). Но мы будем для простоты использовать декларативный способ этапа проектирования.

    Web-форма в оболочке после наших действий будет иметь вид

    Какое представление будет генерировать элемент MultiView, зависит от значения свойства MultiView.ActiveViewIndex, доступного декларативно и программно. Если значение этого свойства равно " -1 ", то при исполнении страницы ни одна из вкладок не будет генерировать HTML-отклик. Если свойство установлено в ноль, то будет работать первая вкладка, и т.д.

    Продолжим выполнение упражнения и наполним представления View1, View2, View3 вариантами содержимого.

  • Командой Add Existing Item добавьте в корневую папку сайта какой-нибудь рисунок Web-формата (*. gif, *. jpg, *. png ), который занимает не очень много места. Один из вариантов рисунка - файл MyPhoto.jpg в прилагаемой папке Source
  • Поместите в представление View1 из вкладки Standard компонент Image (контейнер для рисунка) и через панель Properties декларативно настройте его так:
  • ImageUrl =" ~/MyPhoto.jpg " (символ ' ~ ' тильда обозначает корень виртуального каталога сайта)
  • Поместите в представление View2 какой-нибудь текст
  • Поместите в представление View3 элемент Calendar из вкладки Standard и настройте его внешний вид
  • Выделите объект MultiView1 и установите его свойство ActiveViewIndex в значение ноль, чтобы при начальной загрузке страницы было открыто первое представление
  • После выполненных действий разметка страницы будет описываться следующим кодом

    <%@ Page AutoEventWireup="true" 
        CodeFile="MultiViewControl.aspx.cs" 
        Inherits="MultiViewControl" Language="C#" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления множеством представлений</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                 <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
                    <asp:View ID="View1" runat="server">
                        <h1>Мое фото</h1>
                        <asp:Image ID="Image1" runat="server" ImageUrl="~/MyPhoto.jpg" />
                    </asp:View>
                    
                    <asp:View ID="View2" runat="server">
                        <h1>Мои стихи</h1>
                        <p>
                            У Лукоморья дуб зеленый<br />
                            Златая цепь на дубе том<br />
                            И днем и ночью кот ученый<br />
                            Все ходит по цепи кругом
                        </p>
                    </asp:View>
                    
                    <asp:View ID="View3" runat="server">
                        <h1>Мой календарь</h1>
                        <asp:Calendar ID="Calendar1" runat="server" BackColor="#C0FFFF" 
                            BorderColor="Red" BorderStyle="Ridge">
                        </asp:Calendar>
                    </asp:View>
                </asp:MultiView>
            </div>
        </form>
    </body>
    </html>

    Если сейчас запустить страницу MultiViewControl.aspx на выполнение, то мы увидим только первую раскрытую вкладку с фотографией, а для активизации других вкладок у нас нет пока механизма.

    Управление работой вкладок

    Вариант 1

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

  • Поместите на форму страницы впереди элемента MultiView1 компонент DropDownList из вкладки Standard
  • Установите для списка свойство AutoPostBack в значение True, чтобы при выборе нового пункта автоматически выполнялась обратная отсылка
  • После этих действий дескрипторный код страницы станет таким

    <%@ Page AutoEventWireup="true" 
        CodeFile="MultiViewControl.aspx.cs" 
        Inherits="MultiViewControl" Language="C#" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления множеством представлений</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True" >
                </asp:DropDownList>
                <br />
                <asp:MultiView ID="MultiView1" runat="server" ActiveViewIndex="0">
                    <asp:View ID="View1" runat="server">
                        <h1>Мое фото</h1>
                        <asp:Image ID="Image1" runat="server" ImageUrl="~/MyPhoto.jpg" />
                    </asp:View>
                    
                    <asp:View ID="View2" runat="server">
                        <h1>Мои стихи</h1>
                        <p>
                            У Лукоморья дуб зеленый<br />
                            Златая цепь на дубе том<br />
                            И днем и ночью кот ученый<br />
                            Все ходит по цепи кругом
                        </p>
                    </asp:View>
                    
                    <asp:View ID="View3" runat="server">
                        <h1>Мой календарь</h1>
                        <asp:Calendar ID="Calendar1" runat="server" BackColor="#C0FFFF" 
                            BorderColor="Red" BorderStyle="Ridge">
                        </asp:Calendar>
                    </asp:View>
                </asp:MultiView>
            </div>
        </form>
    </body>
    </html>
  • Выделите экземпляр DropDownList1 и через панель Properties в режиме Events создайте в застраничном файле MultiViewControl.aspx.cs обработчик события SelectedIndexChanged, который заполните так
  • // Обработчик события выбора в списке
        protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
        {
            MultiView1.ActiveViewIndex = DropDownList1.SelectedIndex;
        }
  • Поместите в обработчик события Load застраничного файла MultiViewControl.aspx.cs следующий код
  • protected void Page_Load(object sender, EventArgs e)
        {
            // Заполняем список только при первом запросе страницы,
            // а потом все будет сохраняться в состоянии вида.
            // Иначе список всегда будет переустанавливаться в начало
            if (!IsPostBack)
            {
                // Подсоединяем коллекцию с вкладками к списку
                DropDownList1.DataSource = MultiView1.Views;
                // Назначаем атрибут, значениями которого
                // будут заполнены поля "Text" списка
                DropDownList1.DataTextField = "ID";
                // Заполняем список подсоединенными данными
                DropDownList1.DataBind();
        
                // Отображаем первое представление
                MultiView1.ActiveViewIndex = 0;
                // Синхронизируем список
                DropDownList1.SelectedIndex = 0;
        
                // Выделяем текущую дату 
                Calendar1.SelectedDate = DateTime.Now.Date;
                Calendar1.SelectedDayStyle.BorderStyle = BorderStyle.Solid;
            }
        }
  • Выполните страницу, результат должен быть не менее лучезарным, чем этот...
  • Вариант 2

    В обработчике события Page_Load() мы, для тренировки, вставили код, чтобы при первом запросе страницы список программно заполнялся значениями атрибутов ID представлений. Этого можно и не делать, если вручную на этапе проектирования заполнить свойство Items списка более осмысленными именами.

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

  • Через панель Solution Explorer выполните копию страницы MultiViewControl.aspx и присвойте копии новое имя MultiViewControl1.aspx.
  • Обратите внимание, что файл кода .cs автоматически копируется и переименовывается вместе со страницей. Более того, в оболочке даже не предусмотрена возможность переименовать его отдельно, пока он связан со страницей. Если же его скопировать отдельно, тогда он переименовывается.

  • Выполните команду меню Window/Close All Documents, чтобы закрыть все прежние окна редактирования рабочей области оболочки
  • Откройте новую страницу MultiViewControl1.aspx на редактирование и выполните команду меню Website/Set As Start Page, чтобы сделать ее стартовой при запуске из оболочки
  • Выделите список через панель Properties и сбросьте его свойство AutoPostBack в False
  • Через раскрывающийся список в верхней части панели Properties выделите объект MultiView1 и задайте ActiveViewIndex = -1, чтобы ни одно представление при первой загрузке страницы у пользователя не было раскрыто
  • В файле MultiViewControl1.aspx.cs полностью очистите обработчик события Page_Load(), код которого в предыдущем примере программно заполнял список (можно полностью удалить этот обработчик, нам он здесь не понадобится)
  • Сейчас мы должны заполнить список выбора вкладок декларативно (на этапе проектирования).

  • Выделите список и заполните его свойство Items так
  • Декларативные настройки объекта DropDownList1
    Items[i] Text Value
    Items[0] Моя фотография не имеет значения ...
    Items[1] Мои стихи не имеет значения ...
    Items[2] Встроенный календарь не имеет значения ...
  • Добавьте на новую страницу справа от списка кнопку Input (Submit) из вкладки HTML панели Toolbox (воспользуемся простой кнопкой) и задайте ей следующие настройки:
  • ID = Submit1
  • Value = Show
  • Title = Раскрыть вкладку
  • Запустите приложение и понажимайте кнопку Show, не изменяя список
  • Ничего не происходит, пока в списке мы не выбирем новый пункт. Только после этого свойство MultiView1. ActiveViewIndex примет отличное от -1 значение и представления при обратной отсылке начнут работать. Чтобы исправить это, нужно код присвоения значения свойству ActiveViewIndex переместить из обработчика спискового события SelectedIndexChanged в обработчик щелчка кнопки.

  • Создайте обработчик события Click для кнопки Submit1 двойным щелчком на ней мышью
  • Мы видим, что оболочка создала код заготовки JavaScript -сценария, который мы должны заполнить и который страница готова посылать на клиентский броузер. Это стандартное поведение оболочки при создании обработчиков: если элемент управления на активной странице не помечен как серверный (нет атрибута runat =" server "), значит свою динамику он может реализовать только на стороне клиента в блоке сценариев JavaScript.

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

  • Откатите состояние редактора до шага, предшествующего созданию обработчика, или же выполните следующие действия по очистке кода:
  • Удалите созданный оболочкой предыдущим действием код JavaScript -сценария. Для этого в режиме Source поместите текстовый курсор редактора внутрь блока кода <script language="javascript" type="text/javascript">..|..</script> и в нижней части рамки окна редактора щелкните на кнопке <script>. Весь выделенный код можно удалять
  • Удалите из дескриптора <input> кнопки Submit1 код регистрации обработчика onclick="return Submit1_onclick()", сгенерированный оболочкой
  • Щелкните на Submit1 правой кнопкой мыши и выполните команду Run As Server Control. Этим действием в дескриптор <input> будет добавлен атрибут runat="server", который заставит ASP.NET запускать обработчик кнопки (если мы его предусмотрим), если с броузера с обратной отсылкой будет прислано событие, что клиент щелкал на этой кнопке
  • Выделите список DropDownList1 и через панель Properties в режиме Events очистите поле события SelectedIndexChanged, тем самым оболочка удалит из дескриптора DropDownList1 ссылку на этот обработчик. После этого обработчик станет свободным методом класса, у которого нет неявных вызовов с помощью механизма событий
  • Двойным щелчком на кнопке Submit1, теперь уже серверной, создайте для нее обработчик в файле MultiViewControl1.aspx.cs
  • Перенесите код обработчика события SelectedIndexChanged в код нового обработчика, а старый обработчик события SelectedIndexChanged удалите
  • В результате код файла будет таким

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
      
    public partial class MultiViewControl : System.Web.UI.Page 
    {
        // Обработчик события на кнопке Submit1
        protected void Submit1_ServerClick(object sender, EventArgs e)
        {
            MultiView1.ActiveViewIndex = DropDownList1.SelectedIndex;
        }
    }
  • Выполните страницу и отметьте следующее
  • При первой загрузке страницы обработчик щелчка на кнопке еще не сработал, поскольку не было обратной отсылки, а выполнился только отклик на первый запрос. Но все последующие обратные отсылки страницы выполняются по щелчку клиента на кнопке Submit1 и присылают на сервер информацию о том, что на клиенте произошло событие Click. По прибытию на сервер такой обратной отсылки система ASP.NET распознает присланное событие Click, свойству MultiView1.ActiveViewIndex в обработчике присваивается значение выбранной пользователем опции списка и элемент MultiView1 при формировании текущего отклика генерирует содержимое вкладки, соответствующей этому выбору.

    Добавление к MultiView функций навигации

    На предыдущих шагах мы знакомились с механизмом работы элемента MultiView. Мы использовали для смены вкладок внешний по отношению к MultiView элемент списка DropDownList1. Но MultiView имеет собственные средства для перехода по своим вкладками. Эти возможности основаны на том факте, что серверные элементы Button, ImageButton, LinkButton реализуют интерфейс System.Web.UI.WebControls. IButtonControl, от которого наследуют способность генерировать и распознавать не только событие Click, но и событие Command. Такие элементы управления называются кнопочными. Они реализуют ряд полезных свойств интерфейса, таких как CommandArgument, CommandName и др.

    В свою очередь, элемент управления MultiView содержит общедоступные переменные (поля), которые ожидают поступления определенных команд, чтобы MultiView соответствующим образом их исполнил

    Вот какие значения своих полей ожидает элемент MultiView

    Имена команд, которые может распознать MultiView
    Поле элемента MultiView Ждет команду Описание действия MultiView
    NextViewCommandName NextView Переход к следующему представлению. Команда является значением свойства CommandName кнопочного элемента
    PreviousViewCommandName PrevView Переход к предыдущему представлению. Команда является значением свойства CommandName кнопочного элемента
    SwitchViewByIDCommandName SwitchViewByID Переход к представлению со значением идентификатора ID, переданным из свойства CommandArgument кнопочного элемента управления
    SwitchViewByIndexCommandName SwitchViewByIndex Переход к представлению с определенным индексом, переданным из свойства CommandArgument кнопочного элемента управления

    Добавим в нашу страницу описанную возможность навигации по вкладкам элемента MultiView.

  • В панели Solution Explorer скопируйте страницу MultiViewControl1.aspx, присвойте копии имя MultiViewControl2.aspx и сделайте эту страницу стартовой
  • Из вкладки Standard панели Toolbox поместите в нижнюю часть первой View1 и последней View3 вкладки по одной серверной кнопке Button, а в нижнюю часть средней вкладки View2 - две кнопки
  • Отклик для средней вкладки после размещения в нижней ее части двух кнопок будет таким

  • Настройте кнопки как показано в таблице
  • Настройка кнопок навигации на вкладках
    Вкладка Свойство кнопки Значение
    View1 ID btnNext0
    Text Next >
    CommandName NextView
    View2 ID btnPrev1
    Text < Prev
    CommandName PrevView
    ID btnNext1
    Text Next >
    CommandName NextView
    View3 ID btnPrev2
    Text < Prev
    CommandName PrevView

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

  • Установите редактор страницы в режим Design
  • В панели Properties в верхнем раскрывающемся списке выберите объект MultiView1, переведите панель в режим Events (кнопка с пиктограммой молнии) и двойным щелчком на поле события ActiveViewChanged создайте обработчик, который заполните кодом синхронизации списка
  • В результате файл поддержки страницы должен быть таким

    using System;
    using System.Data;
    using System.Configuration;
    using System.Web;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.UI.WebControls.WebParts;
    using System.Web.UI.HtmlControls;
      
    public partial class MultiViewControl : System.Web.UI.Page 
    {
        // Обработчик события на кнопке Submit1
        // Синхронизация представлений со списком
        protected void Submit1_ServerClick(object sender, EventArgs e)
        {
            MultiView1.ActiveViewIndex = DropDownList1.SelectedIndex;
        }
      
        // Синхронизация списка с представлениями
        protected void MultiView1_ActiveViewChanged(object sender, EventArgs e)
        {
            DropDownList1.SelectedIndex = MultiView1.ActiveViewIndex;
        }
    }

    Файл дескрипторного представления будет таким

    <%@ Page AutoEventWireup="true" 
        CodeFile="MultiViewControl2.aspx.cs" 
        Inherits="MultiViewControl" Language="C#" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления множеством представлений</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:DropDownList ID="DropDownList1" runat="server">
                    <asp:ListItem>Моя фотография</asp:ListItem>
                    <asp:ListItem>Мои стихи </asp:ListItem>
                    <asp:ListItem>Встроенный календарь</asp:ListItem>
                </asp:DropDownList>
                
                <input id="Submit1" type="submit" value="Show" 
                    title="Раскрыть вкладку" runat="server" 
                    onserverclick="Submit1_ServerClick" /><br />
                    
                <asp:MultiView ID="MultiView1" runat="server" 
                    OnActiveViewChanged="MultiView1_ActiveViewChanged">
                    <asp:View ID="View1" runat="server">
                        <h1>
                            Мое фото</h1>
                        <asp:Image ID="Image1" runat="server" 
                            ImageUrl="~/MyPhoto.jpg" /><br />
                        <br />
                        <asp:Button ID="btnNext0" runat="server" 
                            CommandName="NextView" Text="Next >" />
                    </asp:View>
                    
                    <asp:View ID="View2" runat="server">
                        <h1>
                            Мои стихи</h1>
                        <p>
                            У Лукоморья дуб зеленый<br />
                            Златая цепь на дубе том<br />
                            И днем и ночью кот ученый<br />
                            Все ходит по цепи кругом
                        </p>
                        <asp:Button ID="btnPrev1" runat="server" 
                            CommandName="PrevView" Text="< Prev" />
                        <asp:Button ID="btnNext1" runat="server" 
                            CommandName="NextView" Text="Next >" />
                    </asp:View>
                    
                    <asp:View ID="View3" runat="server">
                        <h1>
                            Мой календарь</h1>
                        <asp:Calendar ID="Calendar1" runat="server" 
                            BackColor="#C0FFFF" BorderColor="Red"
                            BorderStyle="Ridge" />
                        <br />
                        <asp:Button ID="btnPrev2" runat="server" 
                            CommandName="PrevView" Text="< Prev" />
                    </asp:View>
                </asp:MultiView>
            </div>
        </form>
    </body>
    </html>
  • Выполните страницу и убедитесь, что все работает как нужно
  • Хороший элемент, что и говорить. Но есть один существенный недостаток. Поскольку хранится несколько представлений, то мы должны быть готовы вернуться к любому представлению, если его повторно вызовет пользователь. Это значит, что мы должны сохранять состояние вида всех представлений, в том числе и невидимых в данный момент. Из-за этого элемент посылает на клиентскую машину большой объем кода состояния вида. От этой неприятности можно избавиться, отключив свойство EnableViewState, но тогда последние пользовательские настройки вкладок текущего сеанса сохраняться не будут.

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

    Упражнение 2. Элемент управления Wizard

    Элемент управления Wizard (мастер) является более развитым, чем элемент MultiView. Он имеет богатую настраиваемую функциональность, включающую в себя

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

  • Добавьте к проекту MultiView новую страницу с именем WizardControl.aspx и файлом отделенного кода. Назначьте ее стартовой
  • В режиме Design редактора поместите на страницу элемент управления Wizard из вкладки Standard панели Toolbox
  • Будет сгенерирована такая заготовка

    Разметка страницы на данном этапе будет представлена следующим кодом

    <%@ Page Language="C#" AutoEventWireup="true" 
        CodeFile="WizardControl.aspx.cs" Inherits="WizardControl" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления Wizard</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Wizard ID="Wizard1" runat="server" ActiveStepIndex="0">
                    <WizardSteps>
                        <asp:WizardStep runat="server" Title="Step 1">
                        </asp:WizardStep>
                        <asp:WizardStep runat="server" Title="Step 2">
                        </asp:WizardStep>
                    </WizardSteps>
                </asp:Wizard>
            </div>
        </form>
    </body>
    </html>

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

    В элементе управления MultiView все представления на этапе проектирования раскрыты для разработчика. Для элемента Wizard оболочка Visual Studio 2005 показывает разработчику вкладку только одного текущего шага.

    Чтобы создать новые шаги мастера, нужно:

  • просто добавлять в его контейнер дескрипторы <asp:WizardStep>
  • или через локальную панель задач выполнить опцию Add/Remove WizardSteps
  • или в панели Properties вызвать на редактирование свойство WizardSteps
  • Обратите внимание, что по умолчанию дескрипторы <asp:WizardStep> шагов -вкладок не имеют значения идентификатора ID. Здесь подразумевается, что для такого сложного элемента управления разработчику достаточно декларативной настройки. Если же в дальнейшем разработчик предполагает программно управлять шагами мастера, то он должен прописать атрибуты ID в дескрипторах шагов.

    В приведенном окне редактирования коллекции шагов -вкладок наиболее существенными являются следующие свойства дескриптора <asp:WizardStep>

    Некоторые свойства дескриптора <asp:WizardStep>
    Свойство Описание
    Title Имя шага, видимое пользователю в ссылках на боковой панели слева
    StepType

    Это свойство определяет тип кнопок навигации, которые будут предъявлены пользователю данным шагом, и равно одному из значений перечисления System.Web.UI.WebControls.WizardStepType.WizardStepType:

  • Auto - определяется по умолчанию и устанавливает тип кнопки в зависимости от местонахождения шага в коллекции. Если шаг стоит на первом месте, то будет кнопка Start, во всех промежуточных позициях - кнопка Step, если на последнем месте - будет кнопка Finish
  • Complete - не показывает никаких кнопок и скрывает боковую панель
  • Finish - показывает кнопки Finish и Previous
  • Start - показывает кнопку Next
  • Step - показывает кнопки Next и Previous
  • AllowReturn Показывает, может ли пользователь возвращаться к этому шагу после того, как его пройдет. Если это свойство имеет значение false, то как только пользователь пройдет этот шаг, он не сможет вернуться назад. Потому что все ссылки, ведущие к этому пройденному шагу, немедленно будут блокированы.

    Наполним шаги мастера конкретным содержимым - элементами управления, и настроим их свойства. Всего создадим четыре шага, в которых разместим:

  • WizardStep1 - раскрывающийся список DropDownList
  • WizardStep2 - список радиокнопок RadioButtonList
  • WizardStep3 - текстовое поле TextBox
  • WizardStep4 - обычный текст
  • Оболочка Visual Studio 2005 все отличные от значений по умолчанию свойства элементов сохраняет в дескрипторах текстового файла .aspx как дополнительные атрибуты. Более того, при установке значений отдельным свойствам оболочка сама генерирует новые дескрипторы и даже целые блоки кода. Поэтому все декларативные настройки сложных элементов управления нужно выполнять через панель Properties, но для краткости изложения приведем уже готовый код настройки страницы нашего примера.

    <%@ Page Language="C#" AutoEventWireup="true" 
        CodeFile="WizardControl.aspx.cs" Inherits="WizardControl" %>
      
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title>Элемент управления Wizard</title>
    </head>
    <body>
        <form id="form1" runat="server">
            <div>
                <asp:Wizard ID="Wizard1" runat="server" BackColor="#EFF3FB" 
                    BorderColor="#B5C7DE"
                    BorderWidth="1px" ActiveStepIndex="0" 
                    StartNextButtonText="Далее >"
                    StepNextButtonText="Далее >" StepPreviousButtonText="< Назад" 
                    FinishCompleteButtonText="Готово" FinishPreviousButtonText="< Назад" 
                    HeaderText="Жизненно важная анкета!">
                    <WizardSteps>
                        <asp:WizardStep ID="WizardStep1" runat="server" Title="Друзья">
                            <h3>
                                Какой президент самый лучший?</h3>
                            <asp:DropDownList ID="DropDownList1" runat="server">
                                <asp:ListItem>Наш Медведев</asp:ListItem>
                                <asp:ListItem>Их Обама</asp:ListItem>
                                <asp:ListItem>Похожий на Чингиз-Хана</asp:ListItem>
                                <asp:ListItem>Вы сами</asp:ListItem>
                                <asp:ListItem>Ваша соседка</asp:ListItem>
                            </asp:DropDownList>
                        </asp:WizardStep>
                        <asp:WizardStep ID="WizardStep2" runat="server" Title="Туризм">
                            <h2>
                                Где Вы были с 19 по 21 августа 1991 года?</h2>
                            <asp:RadioButtonList ID="RadioButtonList1" runat="server">
                                <asp:ListItem>На Красной площади</asp:ListItem>
                                <asp:ListItem>На Луне</asp:ListItem>
                                <asp:ListItem>В чужом огороде</asp:ListItem>
                                <asp:ListItem>У тетеньки</asp:ListItem>
                                <asp:ListItem>В ауте</asp:ListItem>
                            </asp:RadioButtonList>
                        </asp:WizardStep>
                        <asp:WizardStep ID="WizardStep3" runat="server" Title="Встречи">
                            <h3>
                                Кайтесь! Место встречи изменить нельзя!</h3>
                            Ваш ИНН:
                            <asp:TextBox ID="TextBox1" runat="server" />
                        </asp:WizardStep>
                        <asp:WizardStep ID="WizardStep4" runat="server" Title="Досуг">
                            <h2>
                                Мера поощрения</h2>
                            Усиленная диета + клизьма с перцем!
                        </asp:WizardStep>
                    </WizardSteps>
                    <HeaderStyle BackColor="Blue" Font-Bold="True" Font-Size="X-Large" ForeColor="Yellow" />
                </asp:Wizard>
            </div>
        </form>
    </body>
    </html>

    Несколько замечаний:

  • Боковую панель навигационных ссылок можно отключать свойством Wizard.DisplaySideBar =" False "
  • Оболочка в режиме проектирования автоматически изменяет значение свойства Wizard.ActiveStepIndex при редактировании текущего шага. Поэтому, чтобы страница при запуске показала первый шаг, небходимо в конце редактирования либо на него перейти, либо установить Wizard.ActiveStepIndex ="0"
  • Мы еще ничего не программировали, а уже успели добиться такой мощной функциональности страницы
  • Последний дескриптор кода <HeaderStyle> определяет стиль заголовочного блока элемента Wizard
  • Запустите страницу с настроенным элементом Wizard и "подывитесь", какой же все-таки Большой Билл умный, да еще так вовремя - какие масштабы и горизонты открывают для нас эти его инструменты (ну, прямо, Эльдорадо!)
  • Программирование событий элемента управления Wizard

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

    События, поддерживаемые элементом Wizard
    Событие О чем информирует пришедшее от клиента событие
    ActiveStepChanged Пользователь переключился на новый шаг или код внутри страницы изменил свойство ActiveStepIndex
    CancelButtonClick Пользователь щелкнул на кнопке Cancel (Отмена). Кнопка Cancel по умолчанию не отображается, однако ее можно добавить во все представления Step сразу, если установить свойство Wizard.DisplayCancelButton="True". Кнопка Cancel инициирует обратную отсылку, и если не предусмотреть соответствующего обработчика, то ничего не происходит. Но если одновременно определено свойство Wizard.CancelDestinationPageUrl, например, CancelDestinationPageUrl="~/Alternate.aspx", то по щелчку пользователя на этой кнопке ему отправляется другая страница
    FinishButtonClick Пользователь дошел до последнего шага и щелкнул на кнопке Finish
    NextButtonClick, PreviousButtonClick Эти события возникают при щелчке на кнопке Next или Previous на любом шаге. Но сменить шаг пользователь может и через боковую панель. Чтобы такой момент не упустить и однозначно среагировать на смену шага, лучше вместо этих событий обрабатывать событие ActiveStepChanged
    SideBarButtonClick Пользователь щелкнул на ссылке в области боковой панели
    Чувствуете?!!! Мы сидим со своим кодом на другом конце провода (на сервере) и ждем очередных пожеланий ненасытного пользователя. При получении от него очередного запроса мы анализируем выбор по присланным событиям и пакуем для него новую посылку, в которую закладываем и требуемый текущий ответ, и интерфейсные элементы для ввода новых пожеланий. Да все это еще должно быть красивым, блестящим и пушистым. Вот Большой Билл нам здесь и помогает - осталось только руки приложить.

    Используем событие FinishButtonClick, чтобы усовершенствовать наш пример. Когда пользователь щелкнет в последнем шаге -вкладке на кнопке Finish (Готово), соберем его выбор с каждого шага и вернем в раскрытом представлении этого последнего шага.

  • Откройте страницу WizardControl.aspx в режиме Design и перейдите на последний шаг WizardStep4 для его редактирования
  • Поместите в середину области шага текстовую метку Label из вкладки Standard панели Toolbox, присвойте ей имя lblSummary и очистите ее свойство Text
  • Выделите объект Wizard1 и через панель свойств в режиме Events создайте обработчик для события FinishButtonClick
  • Заполните обработчик следующим кодом
  • protected void Wizard1_FinishButtonClick(object sender, WizardNavigationEventArgs e)
        {
            // Библиотека Framework 2.0 в нашем распоряжении
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            sb.Append("<h3>");
            sb.Append("Вы выбрали: <br />");
            string title;
      
            title = WizardStep1.Title;
            sb.Append(title + ": " + DropDownList1.Text + "<br />");
      
            title = WizardStep2.Title;
            int index = RadioButtonList1.SelectedIndex;
            if(index != -1) // Если что-то выбрал
                sb.Append(title + ": " + RadioButtonList1.Items[index].Text + "<br />");
      
            /*  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
            // Для элемента класса CheckBoxList нужно проверять коллекцию:
            CheckBoxList CheckBoxList1;
            foreach (ListItem item in CheckBoxList1.Items)
            {
                if (item.Selected)
                    sb.Append(item.Text + "; ");
            }
                !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
      
            title = WizardStep3.Title;
            if (TextBox1.Text.Length > 0)// Если что-то ввел
                sb.Append(title + ": " + TextBox1.Text + "<br /></br />");
      
            sb.Append("</h3>");
      
            sb.Append("Вам рекомендуется:");
      
            // Отображаем собранные данные
            lblSummary.Text = sb.ToString();
        }

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

  • Перейдите в режиме Design на первый шаг WizardStep1, чтобы автоматически установилось в ноль значение свойства ActiveStepIndex объекта Wizard1 и пользователю вначале отображался первый шаг
  • Выполните страницу, заполните анкету и на последнем шаге щелкните на кнопке Готово
  • Обработчик отобразит пользователю примерно такой результат

    Стили элемента Wizard

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

    Например, для кнопки StartNext применяются следующие свойства:

    Некоторые свойства для настройки кнопок
    Свойство Описание
    StartNextButtonImageUrl Задает изображение для изображения-кнопки
    StartNextButtonStyle Использует стили внешней каскадной таблицы стилей CSS
    StartNextButtonText Настраивает текст кнопки или ссылки
    StartNextButtonType Определяет кнопку, ссылку или выбираемое изображение-кнопку

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

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

    Свойства Wizard, определяющие стили его элементов
    Стиль Описание
    ControlStyle Наследуется Wizard от класса WebControl и применяется ко всем его разделам
    HeaderStyle Применяется к разделу верхнего колонтитула, который будет отображаться только в том случае, если будет задан какой-нибудь текст в свойстве Wizard.HeaderText
    SideBarStyle Применяется к области боковой панели с кнопками
    SideBarButtonStyle Определяет стиль кнопок боковой панели
    StepStyle Применяется к компонентам представления, включенным в текущий шаг
    NavigationStyle Применяется к нижней области шагов, в которых расположены навигационные кнопки
    NavigationButtonStyle Применяется только к кнопкам навигации в области навигации
    StartNextButtonStyle Применяется к кнопке Next в первом шаге, если ее видимость задана свойством StepType=Start
    StepNextButtonStyle Применяется к кнопке Next в промежуточных шагах, если ее видимость задана свойством StepType=Step
    StepPreviousButtonStyle Применяется к кнопке Previous в промежуточных и последнем шагах, если ее видимость задана свойством StepType=Step
    FinishPreviousButtonStyle Применяется к кнопкам Finish и Previous в последнем шаге, если их видимость задана свойством StepType=Finish
    CancelButtonStyle Применяется к кнопке Cancel во всех шагах, если ее видимость задана свойством DisplayCancelButton=True

    Оболочка Visual Studio 2005 позволяет существенно облегчить жизнь разработчика наличием средств автоматизации по настройке типовых стилей, которых в большинстве случаев будет достаточно. Как и при настройке других сложных элементов управления (например, TreeView, Menu ), воспользуемся локальной панелью задач элемента Wizard, чтобы одним махом присвоить профессиональный стиль нашей странице.

  • Откройте страницу WizardControl.aspx в режиме Design и выделите объект Wizard1
  • Откройте локальную панель задач объекта Wizard1, щелкнув на пиктограмме треугольника в его правом верхнем углу
  • Выполните опцию Auto Format и в появившемся диалоговом окне выберите подходящий стиль
  • Окно Auto Format можно вызвать и через контекстное меню элемента Wizard, выполнив одноименную опцию

  • Выполните страницу WizardControl.aspx и убедитесь, что она приобрела профессиональный дизайн
  • Проанализируйте дескрипторное представление страницы, чтобы выяснить, какие свойства дескрипторов стилей позволили добавить такую красоту (у меня бы такое никогда вручную не получилось!!!)
  • Такое волшебство совершили несколько строчек кода, вот они

    <HeaderStyle BackColor="#FFCC66" Font-Bold="True" Font-Size="0.9em" ForeColor="#333333" 
        BorderColor="#FFFBD6" BorderStyle="Solid" BorderWidth="2px" HorizontalAlign="Center" />
    <SideBarStyle BackColor="#990000" Font-Size="0.9em" VerticalAlign="Top" />
    <NavigationButtonStyle BackColor="White" BorderColor="#CC9966" BorderStyle="Solid"
        BorderWidth="1px" Font-Names="Verdana" Font-Size="0.8em" ForeColor="#990000" />
    <SideBarButtonStyle ForeColor="White" />

    В приведенном коде каждый дескриптор настраивает свою область элемента Wizard. Обратите внимание, что приведенный блок кода настройки стилей оболочка добавляет в самый конец контейнера <asp:Wizard></asp:Wizard>, чтобы легче было искать. Если этот блок кода удалить, то мы вернемся к почти прежнему варианту стилей по умолчанию ( почти, потому, что может потребоваться корректировка атрибутов еще в некоторых других местах, например, в дескрипторе <asp:Wizard> - посмотрите сами!).

  • Налюбовавшись сей красотой, вызовите контекстное меню для элемента Wizard и выполните команду Auto Format/Remove Formating, чтобы вернуться на грешную Землю к стилям по умолчанию
  • Шаблоны элемента Wizard

    Если с помощью свойств-стилей нам не удается добиться желаемого эффекта, то можно воспользоваться свойствами-шаблонами. Ниже приведен полный список шаблонов элемента управления Wizard, выбранный как свойства из панели Object Browser

    Шаблоны элемента управления Wizard
    Шаблон или дескриптор Описание
    HeaderTemplate Определяет содержимое области верхнего колонтитула
    SideBarTemplate Определяет боковую панель, которая обычно включает ссылки навигации для каждого шага
    StartNavigationTemplate Определяет кнопку навигации для первого шага, если ее видимость задана свойством StepType=Start
    StepNavigationTemplate Определяет кнопки навигации в промежуточных и последнем шагах, если их видимость задана свойством StepType=Step
    FinishNavigationTemplate Определяет кнопку навигации Finish для последнего шага, если ее видимость задана свойством StepType=Finish

    Формирование шаблона <HeaderTemplate>

    Дескрипторный блок первого шаблона добавляется опцией Edit Templates через локальную панель задач, либо опцией Edit Template через контекстное меню элемента Wizard (одна и та же команда в разных местах по разному называется - Большой Билл тоже человек!).

  • В режиме Design выполните команду Edit Template/Header Template контекстного меню для элемента управления Wizard страницы WizardControl.aspx
  • В появившемся окне введите текст верхнего колонтитула " Это заголовок шага:" (или любую другую Абру-Кадабру, лишь-бы заготовка шаблона создалась, - все равно потом руками редактировать), после чего щелкните на опции End Template Editing локальной панели задач, чтобы завершить создание шаблона заголовка и вернуться в редактор Design
  • Если ничего в поле текста не ввести, то после выхода по опции End Template Editing дескриптор <HeaderTemplate> создан не будет.

  • Перейдите на странице в режим Source, найдите в конце блока кода созданный оболочкой дескриптор <HeaderTemplate> и отредактируйте его так
  • <HeaderTemplate>
        <h2>
            Это заголовок шага:                        
             <%= Wizard1.ActiveStep.Title %> 
        </h2>
    </HeaderTemplate>

    Получается, что мы шаблон заголовка должны заполнять вручную как обычный HTML-текст. Эта возможность оставлена в силу ее простоты (" Уж HTML-то они должны знать!", опрометчиво подумал Большой Билл). И для тренировки мы сами вставили в этот HTML-код операторный внедренный исполнимый блок <%=  имя_переменной_или_выражение  %>. Это обычный прием, применяемый, например, в PHP. При исполнении страницы вместо этого блока в статический текст будет подставлено значение указанной переменной или выражения. Таких блоков в статическом HTML-коде страницы мы можем наставить, сколько угодно. В нашем примере в указанном месте будет подставляться значение атрибута Title текущего шага, которые мы декларативно определили ранее при формировании шагов элемента Wizard.

  • Исполните страницу и вы увидите работу шаблона заголовка в действии
  • Обратите внимание, что хоть ранее мы и задали в панели Properties значение заголовка в свойстве HeaderText="Жизненно важная анкета!" элемента Wizard (этот атрибут и сейчас там присутствует). Эта настройка так и пройдет на страницу отклика, если ее не переопределить в шаблоне. Но как только мы добавили дескриптор шаблона заголовка, оболочка сразу же скрыла это свойство в панели Properties. Отображаться теперь будет именно заголовок шаблона.

    Формирование остальных шаблонов

    Все оставшиеся шаблоны областей элемента Wizard удобней создавать средствами оболочки в силу их сложности. Чтобы создать требуемый дескриптор шаблона, нужно выполнить соответствующую команду Conver to... (в контекстном меню элемента Wizard или его локальной панели). После этого можно приступать к редактированию созданного шаблона, выполнив опцию Edit Template.

    Команда Edit Template вызывает окно редактора шаблонов, в рабочей области которого находится прямоугольный индикатор настройки со своей локальной панелью. Стоит только выделить этот индикатор, сразу в панели Properties появляются доступные для настройки шаблона свойства.

    Завершение редактирования осуществляется командой End Template Editing контекстного меню или локальной панели

    Обратите внимание, что как только какой-то из шаблонов создан, то в меню соответствующая команда меняется с Conver to..., на Reset... Выполнение команды Reset... начисто удаляет дескрипторы соответствующего шаблона. Дескрипторы любого шаблона можно удалить и вручную в режиме Source, но для шаблона заголовка это можно сделать только вручную.

  • Добавьте к элементу Wizard шаблон <SideBarTemplate> и через панель Properties задайте ему свойство ItemStyle/BorderStyle="Outset"
  • Вернитесь в режим Design и убедитесь, что кнопки боковой панели стали выпуклые
  • Выполните страницу, все должно работать
  • Следует всегда помнить, что при всем многообразии настроек стилей и шаблонов интерфейс по умолчанию является самым вывереным с точки зрения экономии ресурсов при обмене с клиентом. Поэтому менять настройки нужно разумно, за неординарный интерфейс потребуется дополнительная плата, к тому же он может стать объектом насмешек искушенных гурманов.

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

  • Удалите шаблон <SideBarTemplate>, выполнив в режиме Design команду Reset SideBarTemplat контекстного меню элемента Wizard, и выберите красивый стандартный стиль Classic через опцию Auto Format того же меню
  • Вернуться к учебному плану