Китай |
Пользовательские элементы управления
Упражнение 2. Программирование пользовательского элемента
До сих пор мы работали только с интерфейсной частью и не использовали код застраничного файла, хотя и создали его. Но чаще всего это нужно делать, чтобы добавить функциональность, которая может понадобиться клиенту.
Воспользуемся стандартным элементом управления LinkButton, который будет снимать с таймера сервера текущее время и отображать его клиенту. Для разнообразия код C# и дескрипторную разметку поместим в одном файле.
- Вызовите мастер для создания пользовательского элемента управления, выполнив команду Website/Add New Item. Установите шаблон в значение Web User Control, сбросьте флажок Place code in separate file и задайте имя файла TimeDisplay.ascx
- Поместите на страницу TimeDisplay.ascx в режиме Design стандартный элемент управления LinkButton из вкладки Standard
- Через панель Properties измените ID элемента на lnkTime
- Двойным щелчком на свободном месте редактора Design создайте обработчик Page_Load()
- При выделенном элементе lnkTime установите панель Properties в режим Events (кнопка с изображением молнии вверху панели), найдите событие Click и двойным щелчком на поле его значения создайте обработчик lnkTime_Click()
- Заполните обработчики кодом, чтобы файл стал таким
<%@ Control Language="C#" ClassName="TimeDisplay" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { RefreshTime(); } protected void lnkTime_Click(object sender, EventArgs e) { RefreshTime(); } public void RefreshTime() { lnkTime.Text = DateTime.Now.ToLongTimeString(); } </script> <asp:LinkButton ID="lnkTime" runat="server" OnClick="lnkTime_Click" />Листинг 32.5. Код файла TimeDisplay.ascx
В коде мы добавили свою функцию RefreshTime(), поскольку ее код нужно вызывать в двух местах. Без этой функции вполне можно обойтись, но мы представили себе, будто ее тело состоит из большого количества строк.
- Чтобы протестировать наш код, добавьте к приложению новую страницу с именем TimeDisplayTest.aspx
- Переведите страницу TimeDisplayTest.aspx в режим Design и перетащите на нее из панели Solution Explorer файл TimeDisplay.ascx с пользовательским элементом управления
В результате оболочка добавит к странице пользовательский элемент управления и зарегистрирует его
<%@ Page Language="C#" %> <%@ Register Src="TimeDisplay.ascx" TagName="TimeDisplay" TagPrefix="uc1" %> <script runat="server"> </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <uc1:TimeDisplay ID="TimeDisplay1" runat="server" /> </div> </form> </body> </html>Листинг 32.6. Код страницы TimeDisplayTest.aspx после добавления пользовательскогоэлемента
- Выполните страницу, которая на клиенте будет такой
При каждом щелчке пользователя на ссылке-кнопке броузер будет инициировать обратную отсылку на сервер, разработанная страница при исполнении снимет с таймера сервера новое значение времени и сгенерирует броузеру соответствующий HTML-отклик.
Что мы только что сделали в нашем упражнении. Мы код, который можно исполнить одной страницей, разделили на две части, выделив типовую часть в отдельный файл, который назвали пользовательским элементом управления. Это напоминает прием упаковки кода в отдельную функцию. Выполним обратную операцию и сосредоточим весь код на одной исполнимой странице.
- Добавьте к проекту страницу TimeDisplay.aspx без файла отделенного кода и назначьте ее стартовой
- Поместите на страницу из вкладки Standard библиотечный элемент управления LinkButton и присвойте ему имя lnkTime
- Создайте на странице обработчики как в пользовательском элементе управления TimeDisplay.ascx и заполните их таким же кодом
<%@ Page Language="C#" %> <script runat="server"> protected void Page_Load(object sender, EventArgs e) { RefreshTime(); } protected void lnkTime_Click(object sender, EventArgs e) { RefreshTime(); } public void RefreshTime() { lnkTime.Text = DateTime.Now.ToLongTimeString(); } </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:LinkButton ID="lnkTime" runat="server" OnClick="lnkTime_Click" /> </div> </form> </body> </html>Листинг 32.7. Код исполнимой страницы TimeDisplay.aspx
- Выполните страницу и убедитесь, что выдается точно такой же результат, как и в случае с промежуточным файлом TimeDisplay.ascx, в котором находится элемент LinkButton и все обработчики
Добавление свойства
Расширим возможности нашего пользовательского элемента управления и добавим в код общедоступное свойство Format, которому будем передавать либо пустую строку, либо строку форматирования. В зависимости от этого пользовательский элемент управления будет способен отображать текущее время на кнопке LinkButton в разных форматах.
- Измените код файла TimeDisplay.ascx следующим образом
<%@ Control Language="C#" ClassName="TimeDisplay" %> <script runat="server"> private string format; // Контролируемое свойством поле public string Format // Определение свойства Format { get { return format; } set { format = value; } } protected void Page_Load(object sender, EventArgs e) { RefreshTime(); } protected void lnkTime_Click(object sender, EventArgs e) { RefreshTime(); } // Значение format задаем в исполнимой странице через атрибут Format public void RefreshTime() { if (format == "") lnkTime.Text = DateTime.Now.ToLongTimeString(); else lnkTime.Text = DateTime.Now.ToString(format); } </script> <asp:LinkButton ID="lnkTime" runat="server" OnClick="lnkTime_Click" />Листинг 32.8. Улучшенный код файла TimeDisplay.ascx
- Измените код тестовой страницы TimeDisplayTest.aspx следующим образом
<%@ Page Language="C#" %> <%@ Register Src="TimeDisplay.ascx" TagName="TimeDisplay" TagPrefix="uc1" %> <script runat="server"> </script> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <uc1:TimeDisplay ID="TimeDisplay1" runat="server" Format="" /> <br /> <br /> <hr /> <br /> <uc1:TimeDisplay ID="TimeDisplay2" runat="server" Format="Сегодня dddd, dd MMMM yyyy<br />Текущее время HH:mm:ss" /> </div> </form> </body> </html>Листинг 32.9. Код тестовой страницы TimeDisplayTest.aspx
Тестовая страница является клиентом пользовательского элемента управления. Именно в дескрипторе элемента на клиенте мы определяем значение добавленного свойства Format как атрибут этого дескриптора. Обратите внимание, что в подсказчике кода IntelliSense, применяемом при редактировании дескриптора пользовательского элемента управления, появилось новое свойство Format.
Представление тестовой страницы с пользовательским элементом управления на броузере клиента будет выглядеть так
Здесь создаются два экземпляра элемента управления TimeDisplay, первый из которых отображает дату в формате по умолчанию, а другой - в заданном формате.
Порядок генерации событий инициализации
При создании пользовательских элементов управления и добавления в них своих свойств важно знать, в каком порядке происходит создание и инициализация объектов на странице, использующей пользовательский элемент управления. Этот порядок следующий:
- Производится удаленный запрос исполнимой страницы и она загружается в память сервера
- Исполнимая страница инициирует загрузку в память пользовательского элемента управления
- Выполняется настройка пользовательского элемента управления присваиванием значений атрибутов, предусмотренных в дескрипторе описания
- Создается объект родительской страницы с уже готовым объектом пользовательского элемента с начальными настройками, определенными свойствами по умолчанию и значениями атрибутов в дескрипторном описании
- Выполняется событие Page.Load родительской страницы, в обработчике Page_Load() которого можно предусмотреть переназначение атрибутов-свойств пользовательского элемента управления
- Выполняется событие Page.Load пользовательского элемента управления
Если мы будем инициализировать пользовательский элемент управления в его обработчике Page_Load(), то он перезапишет все свои настройки, выполненные в родительском коде, поскольку срабатывает последним. Так, если бы в последнем примере обработчик Page_Load() пользовательского элемента управления инициализировал поле format и имел бы вид
protected void Page_Load(object sender, EventArgs e) { format = ""; if (!Page.IsPostBack) RefreshTime(); }
то мы бы всегда получали результат варианта без форматирования, а именно