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

Пользовательские элементы управления

Упражнение 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, первый из которых отображает дату в формате по умолчанию, а другой - в заданном формате.

Порядок генерации событий инициализации

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

  1. Производится удаленный запрос исполнимой страницы и она загружается в память сервера
  2. Исполнимая страница инициирует загрузку в память пользовательского элемента управления
  3. Выполняется настройка пользовательского элемента управления присваиванием значений атрибутов, предусмотренных в дескрипторе описания
  4. Создается объект родительской страницы с уже готовым объектом пользовательского элемента с начальными настройками, определенными свойствами по умолчанию и значениями атрибутов в дескрипторном описании
  5. Выполняется событие Page.Load родительской страницы, в обработчике Page_Load() которого можно предусмотреть переназначение атрибутов-свойств пользовательского элемента управления
  6. Выполняется событие Page.Load пользовательского элемента управления

Если мы будем инициализировать пользовательский элемент управления в его обработчике Page_Load(), то он перезапишет все свои настройки, выполненные в родительском коде, поскольку срабатывает последним. Так, если бы в последнем примере обработчик Page_Load() пользовательского элемента управления инициализировал поле format и имел бы вид

protected void Page_Load(object sender, EventArgs e)
    {
        format = "";
        if (!Page.IsPostBack)
            RefreshTime();
    }

то мы бы всегда получали результат варианта без форматирования, а именно


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