Файлы к лабораторной работе Вы можете скачать здесь.
Пользовательские элементы управления (user control) разрабатывает сам программист в тех случаях, когда стандартные элементы управления его не удовлетворяют или он разработал удачный вариант кода. Такой элемент управления можно многократно использовать на многих страницах и последующие его модернизации немедленно будут отображаться на всех страницах, где он используется. Часто пользовательские элементы управления применяются для стандартизации (единообразия) интерфейса страниц, например, оформления верхнего и нижнего колонтитулов.
Пользовательский элемент управления представляет собой небольшую часть страницы, которая может содержать статический HTML-код и стандартные элементы управления. В пользовательских элементах управления можно предусмотреть свои свойства, методы и события. Пользовательские блоки кода могут многократно использоваться на разных страницах, но только одного сайта. Для применения в другом сайте его либо нужно скопировать в этот сайт, либо создавать библиотечные специальные серверные элементы наподобие стандартных ( custom server control ).
Файл пользовательского элемента управления может содержать
то же самое, что и файл обычной исполнимой страницы, включая
файл поддержки .cs,
статический HTML-код, стандартные элементы управления. Они
получают те же самые события, что и объект Page,
имеют доступ к таким важным объектам-свойствам, как Application, , , . Но есть
и существенные отличия:
.aspx, пользовательские элементы
управления должны храниться в файлах с расширением .ascxPage,
а объект пользовательского элемента управления производится
от класса UserControl .
Но учитывая, что оба класса ( Page и UserConrol )
наследуют класс TemplateControl, они преобретают много одинаковых
свойств и событий от этого класса
.ascx, а должна это делать через .aspx, в который внедряется
ссылка на файл .ascx<html>, <head>, <body>, <form>@Page файл пользовательского
элемента управления содержит @ControlСреда проектирования позволяет видеть внедренный в страницу
пользовательский элемент управления на поверхности конструктора Design страницы.
Заготовку пользовательского
элемента управления легко создает мастер среды проектирования.
Создадим пользовательский элемент управления, который будет
представлять собой простой
Создайте
новый пустой сайт командой File/New/Website с
именем UserControls 
Выполните
команду Website/Add New Item, выберите шаблон Web
User Control и задайте имя Header .ascx
Созданный мастером файл содержит
только одну строку
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="Header.ascx.cs" Inherits="Header" %>
Пользовательский элемент управления редактируется в оболочке
точно также, как и обычная страница. Файл кодовой части .ascx.cs содержит
тот же код, что и для обычной страницы. В данном упражнении
он нам не нужен, поэтому ничего в нем делать не будем.
Поместите
в интерфейсную часть Header .ascx ниже @Control следующую
HTML-разметку<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="Header.ascx.cs" Inherits="Header" %>
<table bgcolor="blue">
<tr>
<td>
<font color="yellow" face="Vernada, Arial" size="6">
<strong>Тестовая страница User Control</strong>
</font>
</td>
</tr>
<tr>
<td align="right">
<font color="white">
<strong>Время создания: апрель 2009г copy; Все права защищены</strong>
</font>
</td>
</tr>
</table>
Эта разметка даст такое визуальное представление
Тестовая страница User Control
Время создания: апрель 2009г $$\copyright$$ Все права защищеныВсе, что будет находиться на одной странице .ascx,
будет представлять собой один завершенный пользовательский
элемент управления, который мы можем вставлять в любое место
исполнимой страницы.
Продолжим выполнение нашего упражнения. Код пользовательского
элемента управления предполагает его использование на одной
или нескольких исполнимых страницах .aspx,
поэтому создадим такую страницу.
Добавьте
командой Website/Add New Item новую страницу с именем HeaderTest.aspx для
внедрения в нее пользовательского элемента управленияЧтобы применить пользовательский элемент управления на странице, нужно выполнить следующие шаги:
@Register ,
помещенной в начале страницы после @Page, нужно
сообщить ASP.NET,
что где-то на странице есть ссылка на пользовательский элемент
управления<form> дескриптор
пользовательского элемента
Добавьте
вручную на страницу HeaderTest.aspx сразу
после @Page следующую строку регистрации<%@ Register Src="Header.ascx" TagPrefix="myElem"
TagName="Header" %>
Мы знаем, что для различения типа библиотечных элементов управления
в начале их дескрипторного представления используется конструкция <префикс : тип_элемента атрибуты...
/>,
например
<asp:TextBox ID="TextBox1" runat="server" />
Здесь asp играет
роль префикса TagPrefix (или
условного пространства имен), а TextBox -
типа элемента управления TagName.
Директива регистрации связывает вместе файл с кодом, имя и
префикс для классификации и позволяет при размещении элемента
на странице применять стандартный синтаксис дескрипторного
представления серверных элементов. Значения myElem и мы
задали произвольно, но далее эти значения на странице мы должны
строго соблюдать, а значение атрибута Src (Source -
источник) означает имя подключаемого файла с пользовательским
элементом управления.
В зарегистрированных обозначениях пользовательского элемента
управления синтаксис его подключения к странице HeaderTest.aspx будет
представлен парным дескриптором
<myElem:Header ID="Header1" runat="server" ></myElem:Header>
или самозакрывающимся дескриптором
<myElem:Header ID="Header1" runat="server" />
Поместите
вручную внутрь дескриптора <form> код
объявления на странице пользовательского элемента управления,
чтобы в результате пользовательская страница HeaderTest.aspx стала
иметь следующую XML-разметку<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="HeaderTest.aspx.cs" Inherits="HeaderTest" %>
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<myElem:Header ID="Header1" runat="server" />
</div>
</form>
</body>
</html>
Обратите внимание, что при добавлении регистрации элемента
управления на страницу подсказчик кода услужливо
предоставляет всю необходимую информацию для правильного написания
синтаксической конструкции.
Мы рассмотрели способ, которым к странице подключается файл
с любым внешним кодом. Этот код реально может быть любой сложности,
включая все мыслимые элементы управления. Обратите внимание,
что код файла не
содержит ссылок на другие страницы и готов использоваться на
любой странице как дополнение.
На файл пользовательского элемента, в свою очередь, может быть помещен другой пользовательский элемент, разработанный ранее. В таком случае этот подключаемый элемент нужно зарегистрировать на родителе точно так же, как это делается при подключении к конечной странице.
Запустите
тестовую страницу на выполнение, должен получиться такой
результат
До сих пор мы работали только с интерфейсной частью и не использовали код застраничного файла, хотя и создали его. Но чаще всего это нужно делать, чтобы добавить функциональность, которая может понадобиться клиенту.
Воспользуемся стандартным
элементом управления LinkButton, который
будет снимать с
Вызовите
мастер для создания пользовательского элемента управления,
выполнив команду 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" />
В коде мы добавили свою функцию 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>
Выполните
страницу, которая на клиенте будет такой
При каждом щелчке пользователя на ссылке-кнопке броузер будет
инициировать обратную отсылку на сервер, разработанная страница
при исполнении снимет с
Что мы только что сделали в нашем упражнении. Мы код, который можно исполнить одной страницей, разделили на две части, выделив типовую часть в отдельный файл, который назвали пользовательским элементом управления. Это напоминает прием упаковки кода в отдельную функцию. Выполним обратную операцию и сосредоточим весь код на одной исполнимой странице.
Добавьте
к проекту страницу 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>
Выполните
страницу и убедитесь, что выдается точно такой же результат,
как и в случае с промежуточным файлом 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" />
Измените
код тестовой страницы 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>
Тестовая страница является клиентом пользовательского элемента
управления. Именно в дескрипторе элемента на клиенте мы определяем
значение добавленного свойства Format как атрибут этого дескриптора.
Обратите внимание, что в подсказчике кода , применяемом
при редактировании дескриптора пользовательского элемента управления,
появилось новое свойство 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();
}
то мы бы всегда получали результат варианта без форматирования, а именно

Иногда приходится создавать специальные классы для организации
взаимодействия между пользовательским элементом
управления и Web-страницей. Создадим
сложный пользовательский элемент управления LinkTable,
предназначенный для генерирования набора гиперссылок в форматированной
таблице. Для удобства часть кода разместим в отдельном самостоятельном
классе LinkTableItem.
Создайте
страницу Web Form с раздельным кодом и именем LinkTableTest.aspx
Сделайте
эту страницу стартовой
Добавьте
к проекту новую папку с зарезервированным именем App_Code.
Для этого в панели Add ASP.NET Folder /App_Code
Через
контекстное меню на созданной папке App_Code выполните
команду Add
New Item и добавьте к приложению новый класс C#
с именем LinkTableItem.cs
Этот класс в своих полях будет хранить информацию, необходимую пользовательскому элементу управления, а через свойства осуществлять доступ к ней.
Заполните
вспомогательный класс в файле LinkTableItem.cs следующим
кодом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;
/// <summary>
/// Вспомогательный класс LinkTableItem
/// </summary>
public class LinkTableItem
{
// Хранимые поля закрытого типа
private string text, url;
// Конструктор по умолчанию
public LinkTableItem()
{
// Пустой конструктор по умолчанию обязателен
// поскольку есть общий конструктор
}
// Общий конструктор
public LinkTableItem(string text, string url)
{
// Внутренним полям присваиваются значения,
// переданные из родительского объекта
this.text = text;
this.url = url;
}
// Определение свойств доступа к внутренним полям
public string Text
{
get { return text; }
set { text = value; }
}
public string Url
{
get { return url; }
set { url = value; }
}
}
Теперь нужно создать пользовательский элемент, который будет управлять этим вспомогательным классом.
Создайте
заготовку пользовательского элемента управления с
отделенным кодом и именем LinkTable.
Для этого выполните команду Add New Item,
вызвав контекстное меню для корневого узла проекта в панели Solution
Explorer и установив шаблон Web User Control 
Поместите
в таблицу пользовательского элемента следующие стандартные
компоненты:Table из вкладки HTML, который будет форматировать
размещение стандартных элементов управленияLabel из
вкладки Standard в верхнюю ячейку
таблицы, который будет определять заголовок набора ссылокImage из вкладки HTML, определяющий рисунок маркера
ссылокDataList из вкладки Data в нижнюю ячейку
таблицыHyperLink из вкладки Standard
Настройте
интерфейсную часть пользовательского элемента управления
так<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="LinkTable.ascx.cs" Inherits="LinkTable" %>
<table cellpadding="2">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small"
ForeColor="#C00000">
<%--Здесь будет заголовок--%>
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img alt="маркер" height="13" src="32_27.gif" width="25">
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
Text='<%# DataBinder.Eval(Container.DataItem, "Text") %>'>
</asp:HyperLink>
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
Дескриптор <img> для красоты определяет
маркер, который вы можете сами изготовить размером 25x13 или
взять из прилагаемого каталога Source (файл 32_27.gif,
который имеет изображение
).
Атрибут alt задает альтернативную надпись
в поле рисунка, если последний не будет найден.
Вызовите
для корневого узла проекта контекстное меню и командой Add Existing Item скопируйте
из прилагаемого каталога Source файл 32_27.gif Теперь пришла пора программно расширить функциональность пользовательского
элемента управления LinkTable.
Вызовите
на редактирование файл LinkTable.ascx.cs и
заполните его следующим кодомusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 LinkTable : System.Web.UI.UserControl
{
public string Title
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
private LinkTableItem[] items;
public LinkTableItem[] Items
{
get { return items; }
set
{
items = value;
// Обновляем сетку
listContent.DataSource = items;
listContent.DataBind();
}
}
}
Разработка пользовательского элемента управления закончена.
Теперь нужно поместить его на пользовательскую тестовую страницу LinkTableTest.aspx,
которую мы создали в самом начале выполнения этого упражнения
и сделали ее стартовой.
Выполните
команду Window/Close All Documents, чтобы закрыть все окна
редактирования
Откройте
через панель Solution Explorer на редактирование
файл LinkTableTest.aspx в
режиме Design и перетащите на форму из этой
панели узел LinkTable.ascx пользовательского
элемента управленияДескрипторное представление тестовой страницы с зарегистрированным на ней пользовательским элементом управления имеет такой вид
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="LinkTableTest.aspx.cs" Inherits="LinkTableTest" %>
<%@ Register Src="LinkTable.ascx" TagName="LinkTable" TagPrefix="uc1" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Тестовая страница сложного элемента управления</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:LinkTable ID="LinkTable1" runat="server" />
</div>
</form>
</body>
</html>
Откройте
на редактирование застраничный файл LinkTableTest.aspx.cs и
заполните его следующим кодомusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 LinkTableTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Формируем заголовок списка
LinkTable1.Title = "Список жизненно важных гиперссылок";
// Создаем список элементов - гиперссылок
LinkTableItem[] items = new LinkTableItem[3];
items[0] = new LinkTableItem("Ссылка №1 к Большому Биллу",
"http://www.microsoft.com");
items[1] = new LinkTableItem("Ссылка №2 к автошколе \"Диалог-Сервис\"",
"http://www.dialog-service.net");
items[2] = new LinkTableItem("Ссылка №3 к затычке JavaScript",
"javascript:void(0)");
LinkTable1.Items = items;
}
}
Запустите
приложение и убедитесь, что генерируемый пользовательским
элементом управления набор гиперссылок работает исправно
Событие - это встроенный механизм C#, с помощью которого автоматически обеспечивается уведомление зарегистрированных объектов о необходимости выполнения ими какого-то действия. Объект предоставляет свои методы-обработчики для реагирования на возникновение определенного события. В этом случае говорят, что объект подписался на некоторое событие. Такой механизм позволяет отдельным объектам обмениваться сообщениями и реагировать на них.
Технически событие представляет собой некую адресную переменную, ссылающуюся на экземпляр класса, поддерживающего событие. Если значение этой ссылки равно null, то событие не произошло, поскольку нет соответствующего объекта. Один объект генерирует событие (создает экземпляр) и посылает уведомление через канал сообщений операционной системы. Другие, подписанные на это событие объекты приложения, получают это сообщение вместе с дополнительной информацией и запускают соответствующие обработчики, предварительно передав им дополнительную информацию в качестве аргументов.
Для объявления адресной переменной события используются делегаты.
С помощью конструктора
На предыдущем шаге мы с помощью вспомогательного класса LinkTableItem могли добавлять в классе
пользовательского элемента управления LinkTableTest новые
гиперссылки типа asp: к элементу asp:.
По щелчку клиента на одной из гиперссылок он безусловно направлялся
по указанному адресу. Теперь же мы хотим перехватывать и распознавать
щелчок на любой гиперссылке для контроля за действиями пользователя.
Сейчас мы не будем оценивать полномочия пользователя, просто
распознаем гиперссылку и выведем ее на экран.
Ранее в дескрипторном представлении пользовательского элемента
управления мы применяли стандартный элемент asp:.
Если посмотреть на класс этого элемента System.Web.UI. через
панель Object
,
то можно увидеть, что он не имеет никаких событий

С другой стороны, класс LinkButton имеет два события, которые
генерирует элемент при выборе пользователя

Эти события мы и будем перехватывать в нашем элементе управления.
Измените
в шаблоне <ItemTemplate> дескрипторного
представления файла LinkTable.ascx имя элемента HyperLink на LinkButton и
имя атрибута NavigateUrl на CommandArgument,
после чего файл должен стать таким<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="LinkTable.ascx.cs" Inherits="LinkTable" %>
<table cellpadding="2">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small"
ForeColor="#C00000">
<%--Здесь будет заголовок--%>
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img alt="маркер" height="13" src="32_27.gif" width="25">
<asp:LinkButton ID="HyperLink1" runat="server"
CommandArgument='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
Text='<%# DataBinder.Eval(Container.DataItem, "Text") %>'>
</asp:LinkButton>
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
Мы хотим создать событие с именем LinkClicked.
Для распознавания выбранного пункта списка нам вместе с будущим
событием LinkCliked нужно
будет передавать информацию о значениях свойств Text и Url,
которые мы определили ранее во вспомогательном классе LinkTableItem.cs.
Затем в обработчике события LinkClicked мы
распознаем эту информацию и выведем ее на экран.
Напрямую экземпляр класса LinkTableItem.cs в
аргументах события передавать нельзя - не тот тип, поэтому
упакуем его в класс LinkTableEventArgs,
который будет наследником библиотечного класса System.EventArgs.
Объявим также
Откройте
файл LinkTable.ascx.cs пользовательского
элемента управления и добавьте в него объявление нового класса
и using System;
using System.Data;
using System.Configuration;
using System.Collections;
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 LinkTable : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public string Title
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
private LinkTableItem[] items;
public LinkTableItem[] Items
{
get { return items; }
set
{
items = value;
// Обновляем сетку
listContent.DataSource = items;
listContent.DataBind();
}
}
}
// Объявляем делегат будущего события LinkClicked,
// который определит сигнатуру события и обработчика
public delegate void LinkClickedEventHandler(object sender, LinkTableEventArgs e);
// Класс-упаковка экземпляра LinkTableItem для
// передачи с событием в качестве аргумента
public class LinkTableEventArgs : EventArgs
{
// Конструктор
public LinkTableEventArgs(LinkTableItem item)
{
selectedItem = item;
}
// Внутреннее поле будет хранить объект гиперссылки
// и контролируется свойством "только для чтения"
private LinkTableItem selectedItem;
public LinkTableItem SelectedItem
{
get { return selectedItem; }
}
// Внутренне поле хранит флаг отмены, переданный сгенерировавшим
// событие классом-источником для обработчика класса-приемника
private bool cancel = false;// Инициализируется при создании
public bool Cancel
{
get { return cancel; }
set { cancel = value; }
}
}
Таким образом, мы объявили класс для упаковки передаваемой
в событии информации. мы также объявили LinkClicked отправит
эту информацию в канал сообщений Windows.
Конечно же, этим должен заниматься класс LinkTable поддержки
пользовательского элемента управления.
Откройте
на редактирование файл LinkTable.ascx в
режиме Design
Выделите
пользовательский элемент управления listContent и
в панели Properties двойным щелчком на
поле события ItemCommand создайте обработчик
с именем по умолчанию
Добавьте
в класс LinkTable и созданный обработчик
стандартного события ItemCommand следующий кодpublic partial class LinkTable : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public string Title
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
private LinkTableItem[] items;
public LinkTableItem[] Items
{
get { return items; }
set
{
items = value;
// Обновляем сетку
listContent.DataSource = items;
listContent.DataBind();
}
}
// Объявляем в классе наше событие LinkClicked
// с помощью ранее созданного глобального делегата
public event LinkClickedEventHandler LinkClicked;
protected void listContent_ItemCommand(object source, DataListCommandEventArgs e)
{
if (LinkClicked != null)
{
// Выделяем объект ссылки, на которой был выполнен щелчок
LinkButton link = (LinkButton)e.Item.Controls[1];
// Выделяем нужные свойства Text и Url через атрибуты
// дескриптора элемента LinkButton и сохраняем их
// в экземпляре вспомогательного класса
LinkTableItem item = new LinkTableItem(link.Text, link.CommandArgument);
// Передаем ссылку на сохраненные свойства в класс упаковки аргументов
LinkTableEventArgs args = new LinkTableEventArgs(item);
// Генерируем событие
LinkClicked(this, args);
// Пускаем клиента по ссылке, если класс-получатель не запретил
if (args.Cancel != true)
{
Response.Redirect(item.Url);
}
}
}
}
Теперь событие LinkClicked будет возникать
всякий раз, когда пользователь щелкнет на гиперссылке пользовательского
элемента управления. Классом-получателем этого события определим
нашу тестовую страницу. Именно в ней мы создадим функцию-обработчик,
которая распакует переданные событием аргументы и выведет полученную
информацию на экран. Проверку существования события мы выполняем
на случай, чтобы наверняка предотвратить генерацию системного
исключения, если не существует ни одного обработчика.
Учитывая, что в режиме проектирования оболочка поддерживает
автоматическое создание обработчиков через панель Properties только
для событий библиотечных классов, создадим заготовку обработчика
вручную. При этом нужно соблюсти оболочки
нам помогает.
Откройте
на редактирование файл LinkTableTest.aspx.cs и
в конце обработчика события Page_Load() класса LinkTableTest начните
набирать LinkTable1, под которым
на тестовой странице у нас числится экземпляр зарегистрированного
на ней пользовательского элемента управления. Вы сразу увидите
реакцию подсказчика кода IntelliSense 
Нажав два раза клавишу Tab мы получим и
регистрацию события в классе-приемнике через глобального
LinkTable1.LinkClicked += new LinkClickedEventHandler(LinkTable1_LinkClicked);
Если выбрать второй способ, тогда нужно в дескрипторном представлении
пользовательского элемента добавить атрибут OnLinkClicked="LinkTable1_LinkClicked",
чтобы привязать к событию созданный обработчик (обратите внимание,
что имя атрибута формируется из имени события и префикса On ).
Но и в этом случае подсказчик кода нам тоже помогает

Выберем второй способ регистрации обработчика для события LinkClicked.
Уничтожте
регистрацию события в классе LinkTableTest,
скопируйте имя сгенерированного обработчика и добавьте его
в атрибут OnLinkClicked="LinkTable1_LinkClicked" дескриптора <uc1:LinkTable
ID="LinkTable1" runat="server" /> файла
тестовой страницы LinkTableTest.aspx
В режиме Design тестовой страницы разместите последней
текстовую метку asp:Label из вкладки Standard,
задайте ей имя lblInfo и
очистите поле ее свойства Text (либо
удалите одноименный атрибут в дескрипторе). В ней мы будем
отображать информацию о нажатой гиперссылке
Вернитесь
в файл LinkTest.aspx.cs и заполните обработчик такprotected void LinkTable1_LinkClicked(object sender, LinkTableEventArgs e)
{
// Ищем подстроку в вызывающей строке
if (e.SelectedItem.Text.IndexOf("Диалог-Сервис") > 0)
{
e.Cancel = false;// Пропустить
}
else
{
e.Cancel = true; // Не пускаем дальше
lblInfo.Text = "Вы щелкнули " +
"\"" + e.SelectedItem.Text + "\".";
lblInfo.Text += " Извините, но Вам не разрешено идти на " +
e.SelectedItem.Url + "!!!";
}
}
Запустите
тестовую страницу LinkTableTest.aspx и полюбуйтесь
на свою работу
Web-страница, которая содержит интегрированный в нее пользовательский элемент управления, не может без дополнительных приемов получать доступ к компонентам этого элемента: к его методам, событиям, свойствам. Такое положение является обоснованным, чтобы случайно в Web-странице не внести нежелательные изменения в ее дочерний элемент.
Но учитывая, что сам пользовательский элемент имеет доступ к своим компонентам, а страница имеет доступ к пользовательскому элементу, это правило можно обойти. Для этого существует два способа:
В пользовательский элемент вводят промежуточные
свойства или private упаковывают
в функции доступа public, которые сами
видят эти переменные, а их, в свою очередь, видят клиенты
этого класса.
Пусть, например, пользовательский элемент управления MyControl1 как
объект порождается классом MyControl и в качестве
одного из компонентов содержит в себе объект Label1 библиотечного
класса System.Web.UI.. Класс Label наследует от System.Web.UI. свойство BackColor, которое, в свою очередь, имеет
тип System.Drawing.Color. Напрямую из Web-страницы
нельзя установить новое значение свойства BackColor компонента Label1 пользовательского элемента. Но можно
открыть доступ к этому свойству для Web-страницы, введя промежуточное
свойство BackColor (или
с другим именем) в классе самого пользовательского элемента.
Сказанное схематично изображено на рисунке

Выполним это на практике.
Создайте
заготовку пользовательского элемента Web User Control с
именем MyControl.ascx с
раздельным кодом (флажок Place code in separate file мастера
включен)
Перейдите
в режим Design редактора заготовки и
поместите на нее из вкладки Standard элемент Label с
именем Label1
В панели Solution Explorer откройте файл отделенного
кода MyControl.ascx.cs,
удалите из класса MyControl заготовку
обработчика Page_Load() за ненадобностью
и дополните using System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControl : System.Web.UI.UserControl
{
public string Text
{
get { return Label1.Text; }
set { Label1.Text = value; }
}
public System.Drawing.Color BackColor
{
get { return Label1.BackColor; }
set { Label1.BackColor = value; }
}
public System.Drawing.Color ForeColor
{
get { return Label1.ForeColor; }
set { Label1.ForeColor = value; }
}
}
Здесь для свойств доступа мы использовали имена точно такие,
как у прямых свойств компонента Label1.
Но это не обязательно, можно использовать любые имена.
Создайте
пользовательскую тестовую страницу с раздельным кодом под
именем MyControlTest.aspx и
переведите ее в режим редактирования Design
Из
панели Solution Explorer из дерева файлов
приложения перенесите на тестовую страницу узел MyControl.ascx.
Убедитесь, что экземпляр пользовательского элемента управления
зарегистрировался на тестовой странице под именем MyControl1
Попробуйте
выделить добавленный пользовательский элемент управления
и убедитесь, что он не выделяется и добавленные нами свойства
не видны в панели Properties Если пытаться устанавливать начальные настройки пользовательского элемента через атрибуты его дескриптора, то подсказчик кода сообщит, что это возможно, поскольку введенные нами вспомогательные свойства доступны из клиентской страницы

Аналогичным образом, введенные свойства доступны и из программного кода клиентской страницы через имя экземпляра пользовательского элемента, в чем мы сейчас и убедимся на практике.
Поместите
на страницу под пользовательским элементом управления компонент RadioButtonList из
вкладки Standard и
убедитесь, что он имеет ID="RadioButtonList1"
Через
коллекцию Items элемента RadioButtonList1 задайте
три радиокнопки с такими свойствами
Установите
свойство RepeatDirection элемента RadioButtonList1 в
значение Horozontal
Выделите
компонент RadioButtonList1 и через панель Properties создайте обработчик для его события SelectedIndexChanged
Под
списком радиокнопок поместите компонент Input (Submit) из
вкладки HTMLДескрипторное представление страницы будет иметь вид
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="MyControlTest.aspx.cs"
Inherits="MyControlTest" %>
<%@ Register Src="MyControl.ascx" TagName="MyControl" TagPrefix="uc1" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:MyControl ID="MyControl1" runat="server" />
<br />
<br />
<asp:RadioButtonList ID="RadioButtonList1" runat="server"
RepeatDirection="Horizontal"
OnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged">
<asp:ListItem Value="Red">Красный</asp:ListItem>
<asp:ListItem Value="Green">Зеленый</asp:ListItem>
<asp:ListItem Value="Blue">Синий</asp:ListItem>
</asp:RadioButtonList></div>
<br />
<input id="Submit1" type="submit" value="submit" />
</form>
</body>
</html>
Мы хотим, чтобы на клиенте при щелчке на кнопке Submit выполнялась
обратная отсылка на сервер, где код страницы через
введенные нами в класс пользовательского элемента управления
дополнительные свойства менял бы настройку элемента Label1.
Этот код смены настройки нужно поместить в созданный нами обработчик
радиокнопок, чтобы он срабатывал каждый раз, когда получит
обратную отсылку с требованием пользователя выполнить новые
настройки. В результате элемент Label1 сгенерирует
нужный HTML-код
и отошлет его клиенту.
Заполните
обработчик RadioButtonList1_SelectedIndexChanged() страницы в файле MyControlTest.aspx.cs следующим кодомusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlTest : System.Web.UI.Page
{
protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)
{
int index = RadioButtonList1.SelectedIndex;
switch (index)
{
case 0:
MyControl1.ForeColor = System.Drawing.Color.White;
MyControl1.BackColor = System.Drawing.Color.Red;
break;
case 1:
MyControl1.ForeColor = System.Drawing.Color.Aqua;
MyControl1.BackColor = System.Drawing.Color.Green;
break;
case 2:
MyControl1.ForeColor = System.Drawing.Color.Yellow;
MyControl1.BackColor = System.Drawing.Color.Blue;
break;
}
if(index != -1)
MyControl1.Text = RadioButtonList1.Items[index].Value;
}
}
Выполните
страницу и убедитесь, что при щелчке на
кнопке код исполнимой страницы меняет свойства компонента Label1 через
добавленные нами дополнительные глобальные свойства
Есть еще один способ обеспечить доступ к компонентам, интегрированным
в пользовательский элемент управления, это добавить в пользовательский
элемент по дополнительному свойству, возвращающее ссылку на
каждый компонент. При этом нужно использовать только get -аксессоры,
поскольку адреса компонентов менять нельзя. В дальнейшем через
это свойство-ссылку, доступную из страницы, можно
обратиться к любым членам раскрытого таким образом компонента,
входящего в состав пользовательского элемента.
Скопируйте
через панель Solution Explorer , как это
мы делали ранее, файл исполнимой страницы MyControlTest.aspx и
файл пользовательского элемента управления MyControl.ascx
Присвойте
копиям новые имена MyControlTestExt.aspx и MyControlExt.ascx соответственно
(сопровождающие застраничные кодовые файлы оболочка переименует
автоматически)
Сделайте
страницу MyControlTestExt.aspx стартовой,
выполнив на ее узле в панели Solution Explorer команду Set
As Start Page
Измените
в файле MyControlTestExt.aspx значение
параметра Inherits на Inherits="MyControlTestExt" @Page
Измените
параметр Src MyControlTestExt.aspx<%@
Откройте
файл скрытого кода MyControlExt.ascx.cs и
измените в нем класс MyControl, чтобы он выглядел такusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlExt : System.Web.UI.UserControl
{
// Раскрываем весь компонент Label1
// Имя свойства InnerLabel1 выбрали произвольно
// Используется только get-аксессор
public Label InnerLabel1
{
get { return Label1; }
}
}
Скорректируйте
в файле MyControlExt.ascx атрибут Control так Inherits="MyControlExt"
Откройте
файл MyControlTestExt.aspx.cs скрытого кода
тестовой страницы и отредактируйте его для доступа
к прямым свойствам компонента Label1 с использованием
созданного адреса InnerLabel1using System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlTestExt : System.Web.UI.Page
{
protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)
{
int index = RadioButtonList1.SelectedIndex;
// Доступ к прямым свойствам компонента Label1 выполняем
// через ссылку на этот компонент в родителе MyControl1
switch (index)
{
case 0:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.White;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Red;
break;
case 1:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Aqua;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Green;
break;
case 2:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Yellow;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Blue;
break;
}
if(index != -1)
MyControl1.InnerLabel1.Text = RadioButtonList1.Items[index].Value;
}
}
Выполните
страницу и убедитесь, что получился тот же самый результат,
что и в предыдущем примере при реализации первого способа
Какой способ выбрать - решает программист!
На протяжении этой темы мы рассматривали вопрос создания пользовательского элемента управления в режиме проектирования и последующее управление им в программном режиме. Но может потребоваться на странице подгружать и настраивать пользовательский элемент управления динамически ("на лету").
Для динамического создания пользовательского элемента управления ребуется выполнить следующие шаги:
Page.Load экземпляр
класса пользовательского элемента управления, заранее подготовленного
в файлах *.ascx и *.ascx.cs.
Создание и регистрация экземпляра пользовательского элемента
в коде исполнимой страницы осуществляется Page.LoadControl().PlaceHolder место
размещения для точного ID пользовательского
элемента управления, особенно, когда создается несколько
экземпляров одного и того же элемента. Это может понадобиться
для однозначной идентификации элемента в коде страницы при
поиске ссылки на экземпляр, выполняемом с помощью статического
метода Page.FindControl(),
который как раз использует значение идентификатора ID.Есть некоторая специфика динамического создания пользовательского
элемента управления по сравнению с библиотечным компонентом.
Нельзя создать пользовательский элемент напрямую, как это делается
с библиотечным элементом управления через *.ascx.cs,
но и дескрипторной части файла *.ascx. Поэтому
на ASP.NET объединением
этих двух частей на этапе выполнения.
Скопируйте
через панель Solution Explorer , как это
мы делали ранее, файл тестовой страницы MyControlTestExt.aspx и
файл пользовательского элемента управления MyControlExt.ascx
Присвойте
копиям новые имена MyControlDynamicTest.aspx и MyControlDynamic.ascx соответственно
(застраничные файлы оболочка переименует
автоматически)
Сделайте
страницу MyControlDynamicTest.aspx стартовой,
выполнив на ее узле в панели Solution Explorer команду Set
As Start Page
Откройте
файл MyControlDynamic.ascx в режиме Source и исправьте в директиве @Control атрибут подключаемого класса
так Inherits =" MyControlDynamic "
Откройте
застраничный файл MyControlDynamic.ascx.cs и измените имя
класса на MyControlDynamic
Закройте
все предыдущие редактируемые документы командой меню Window/Close
All Documents
Откройте
на редактирование страницу MyControlDynamicTest.aspx в
режиме Design, удалите
наш пользовательский элемент управления Label1 и
поместите на его место из вкладки Standard стандартный
элемент управления PlaceHolder
Перейдите
в файле MyControlDynamicTest.aspx в режим Source редактора
страницы, откорректируйте атрибут Inherits =" MyControlDynamicTest " и
удалите полностью старый код <%@
В этом
же файле MyControlDynamicTest.aspx в
режиме Source удалите
из дескриптора <asp:RadioButtonList> атрибут
регистрации обработчикаOnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged"
На данном этапе страница в дескрипторном представлении будет такой
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="MyControlDynamicTest.aspx.cs"
Inherits="MyControlDynamicTest" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder ID="PlaceHolder1" runat="server" />
<br />
<br />
<asp:RadioButtonList ID="RadioButtonList1" runat="server"
RepeatDirection="Horizontal">
<asp:ListItem Value="Red">Красный</asp:ListItem>
<asp:ListItem Value="Green">Зеленый</asp:ListItem>
<asp:ListItem Value="Blue">Синий</asp:ListItem>
</asp:RadioButtonList>
<br />
<input id="Submit1" type="submit" value="submit" />
</div>
</form>
</body>
</html>
Теперь пользовательский элемент управления на странице
не существует, а вместо него вставлен заменитель пустого
места PlaceHolder1.
Далее мы программно должны создать пользовательский элемент,
добавить ссылку на него к странице, а затем можно управлять
свойствами его компонентов.
Откройте
на редактирование застраничный MyControlDynamicTest.aspx.cs,
выполнив команду контекстного меню View Code редактора
Измените
код обработчика Page_Load(), чтобы он
стал такимusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlDynamicTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Создаем экземпляр класса поддержки
// пользовательского элемента управления
MyControlDynamic MyControl1 = (MyControlDynamic)
Page.LoadControl("MyControlDynamic.ascx");
// Добавляем объект в зарезервированное место страницы
PlaceHolder1.Controls.Add(MyControl1);
int index = RadioButtonList1.SelectedIndex;
// Доступ к прямым свойствам компонента Label1 выполняем
// через ссылку на этот компонент в родителе MyControl1
switch (index)
{
case 0:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.White;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Red;
break;
case 1:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Aqua;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Green;
break;
case 2:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Yellow;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Blue;
break;
}
if(index != -1)
MyControl1.InnerLabel1.Text = RadioButtonList1.Items[index].Value;
}
}
Обратите внимание, что при наборе кода создания пользовательского
элемента в нам не помогает,
потому что страница не знает, что где-то в файле MyControlDynamic.ascx существует
класс MyControl.
Запустите
страницу MyControlDynamicTest.aspx на выполнение
и убедитесь в работоспособности результата, как будто-бы
пользовательский элемент был помещен на исполнимую страницу
в декларативном режиме
Итак, мы разработали несколько пользовательских элементов управления:
Header .ascx - TimeDisplay.ascx - кнопка-ссылка, возвращающая неформатированную
и форматированную дату-времяLinkTable.ascx - список гиперссылок с
предварительным анализом выбора пользователя (для этого создали
свое событие)MyControl.ascx - с применением промежуточных средств доступа
к настройкам внутренних компонентовMyControlExt.ascx - с созданием общего свойства-ссылки
на встроенный компонент для доступа к любым его членамMyControlDynamic.ascx - то же самое, что и MyControlExt.ascx,
только применяли способ динамической загрузки пользовательского
элемента на тестовую страницуДля каждого из этих элементов управления разрабатывалась своя тестовая страница, на которую элемент управления помещался декларативно. Только в последнем случае мы сам пользовательский элемент не изменяли, но на тестовой странице создавали его динамически (программно).
В этом упражнении рассмотрим вопрос, когда на одну страницу нужно поместить программно сразу несколько разных пользовательских элементов управления.
Создайте
новую страницу DynamicUserControls.aspx с
раздельным кодом и сделайте ее стартовой
В раскрывающемся
списке панели Properties выберите элемент DOCUMENT и
задайте его свойству Title значение Портальные
каркасы
В режиме Design поместите с вкладки Standard элемент Panel и
присвойте ему имя Panel1 (оно
генерируется автоматически). Этот элемент будет служить
контейнером для других элементов управления, в том числе
и для пользовательского
Поместите
внутрь контейнера Panel1 друг за другом по вертикали стандартные
элементыDropDownList с автоматически сгенерированным
именем DropDownList1 -
для выбора загружаемого в контейнер пользовательского
элемента управленияPlaceHolder с автоматически сгенерированным
именем PlaceHolder1 -
для Label с автоматически сгенерированным
именем Label1 -
для отображения имени файла, из которого в контейнер загружен
пользовательский элемент управленияИнтерфейс страницы на

По большому счету нам в данном примере безразлично, какие
имена будут иметь экземпляры дочерних элементов. Однозначно
различать их в коде мы можем по найденным ссылкам. Ссылки,
в свою очередь, будем искать в именованном контейнере-панели
по типу дочернего элемента, поскольку помещенные нами элементы
имеют разный тип. Но сама оболочка Visual
Studio 2005 требует, чтобы на странице не было
декларативно объявляемых дескрипторов с одинаковыми значениями ID.
Проследите
в дескрипторном представлении страницы, чтобы ни один из
элементов, включая контейнер, не имел атрибутов Width и Height,
ограничивающих свободную Заметим, что контейнер Panel1, как
родитель, по умолчанию будет определять основные свойства своих
дочерних элементов, такие как
Ранее мы перечислили пользовательские элементы управления,
которые создали в данной работе. Выберем несколько их них для
динамического размещения. Имена этих элементов нужно занести
в список DropDownList1. Пусть это будут элементы:
Header .ascx - TimeDisplay.ascx - Кнопка 'время-дата'LinkTable.ascx - Контролируемый список
гиперссылокMyControl.ascx - С настройкой внутренних
компонентов
Выделите
объект DropDownList1 в
контейнере Place1 и заполните декларативно его
свойство Items так| Items[i] | Text | Value |
|---|---|---|
| Items[0] | (None) |
None |
| Items[1] | |
HeaderTest.ascx |
| Items[2] | Кнопка 'время-дата' |
TimeDisplayTest.ascx |
| Items[3] | Контролируемый
список гиперссылок |
LinkTableTest.ascx |
| Items[4] | С настройкой внутренних
компонентов |
MyControlTest.ascx |
В скрытом
поле Value мы указали имена файлов, которые
в будущем должны будем создать.
Установите
для элемента DropDownList1 его свойство AutoPostBack в значение True,
чтобы обеспечить постинг страницы при выборе пользователем
нужной опцииБудем считать, что один из трех стандартных элементов управления контейнера, а именно список, мы заполнили декларативно. Два других элемента контейнера будем заполнять программно.
Таким образом, один контейнер
мы почти настроили. Но мы хотим разместить на странице дополнительно
еще два таких контейнера, чтобы иметь возможность в каждый
из них программно загружать выбранные через список DropDownList1 пользовательские
элементы управления. При этом мы хотим убедиться, что они
работают независимо друг от друга и каждый делает то, что
должен путем реагирования на свои собственные события.
Через
раскрывающийся список панели Properties выделите
контейнер Panel1 и
настройте его свойства такBackColor = Web/Gainsboro -
BorderWidth = 1px -
толщина рамкиHorizontalAlign = Center -
расположение дочерних элементовBorderStyle = Ridge -
стиль контейнераEnableViewState =" False " -
отключить механизм сохранения состояния вида
В
режиме Design разрабатываемой страницы DynamicUserControls.aspx разместите
на ней по вертикали друг за другом еще две копии контейнера Place1 вместе
с его дочерними элементами и присвойте им имена Panel2, Panel3Мы закончили

Дескрипторное представление страницы должно быть таким
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="DynamicUserControls.aspx.cs" Inherits="DynamicUserControls" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Портальные каркасы</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel ID="Panel1" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
EnableViewState="False" HorizontalAlign="Center">
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True">
<asp:ListItem Value="None">(None)</asp:ListItem>
<asp:ListItem Value="HeaderTest.ascx">Верхний колонтитул</asp:ListItem>
<asp:ListItem Value="TimeDisplayTest.ascx">Кнопка 'время-дата'</asp:ListItem>
<asp:ListItem Value="LinkTableTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label></asp:Panel>
<br />
<asp:Panel ID="Panel2" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
EnableViewState="False" HorizontalAlign="Center">
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="True">
<asp:ListItem Value="None">(None)</asp:ListItem>
<asp:ListItem Value="HeaderTest.ascx">Верхний колонтитул</asp:ListItem>
<asp:ListItem Value="TimeDisplayTest.ascx">Кнопка 'время-дата'</asp:ListItem>
<asp:ListItem Value="LinkTableTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Label ID="Label2" runat="server" Text="Label"></asp:Label></asp:Panel>
<br />
<asp:Panel ID="Panel3" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
EnableViewState="False" HorizontalAlign="Center">
<asp:DropDownList ID="DropDownList3" runat="server" AutoPostBack="True">
<asp:ListItem Value="None">(None)</asp:ListItem>
<asp:ListItem Value="HeaderTest.ascx">Верхний колонтитул</asp:ListItem>
<asp:ListItem Value="TimeDisplayTest.ascx">Кнопка 'время-дата'</asp:ListItem>
<asp:ListItem Value="LinkTableTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder3" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Label ID="Label3" runat="server" Text="Label"></asp:Label></asp:Panel>
</div>
</form>
</body>
</html>
Выполните
сформированную страницу DynamicUserControls.aspx,
чтобы убедиться в работоспособности настроек режима проектированияМы выполнили интерфейсную заготовку портальных
каркасов на исполнимой странице. Теперь пришла пора наполнить
их функциональностью, которая бы обеспечила контейнерную загрузку
выбранных пользовательских элементов управления. Эту функциональность
мы обеспечим, кодируя застраничный файл DynamicUserControls.aspx.cs.
Ниже мы убедимся, что программно загруженные в портальные каркасы пользовательские элементы управления обрабатывают свои события точно также, как будто бы каждый из них находится на отдельной исполнимой странице.
Откройте
на редактирование файл DynamicUserControls.aspx.cs и
добавьте в класс DynamicUserControls следующий
кодusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 DynamicUserControls : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Загружаем портальные каркасы
MyLoadControls(Panel1);
MyLoadControls(Panel2);
MyLoadControls(Panel3);
}
// Вспомогательная функция
private void MyLoadControls(Control containerPanel)
{
// Объявляем вспомогательные ссылки на интерфейсные
// элементы текущего контейнера
DropDownList list = null;
PlaceHolder ph = null;
Label lbl = null;
// Перебираем все дочерние элементы текущего
// контейнера и ищем ссылки на объекты дочерних
// интерфейсных элементов по их типам
foreach (Control ctrl in containerPanel.Controls)
{
if (ctrl is DropDownList)
list = (DropDownList)ctrl;
else if (ctrl is PlaceHolder)
ph = (PlaceHolder)ctrl;
else if (ctrl is Label)
lbl = (Label)ctrl;
}
// Берем информацию из выделенного
// элемента списка текущего контейнера
string lstValue = list.SelectedItem.Value;
string lstText = list.SelectedItem.Text;
lbl.Text = "";
// Заполняем текущий контейнер.
// Проверяем наличие нужного расширения
if (lstValue.EndsWith(".ascx"))
{
ph.Controls.Add(Page.LoadControl(lstValue));
lbl.Text = "Загрузили: " + lstValue + " - " + lstText;
}
}
}
Пользовательский элемент управления иногда проще сделать из
обычной страницы .aspx, выполнив следующие
шаги:
aspx,
отладить ее и проверить в действииaspx в ascx@Page вместе с ее атрибутами
следует удалить и заменить @Control с
требуемыми атрибутами<html>, <body>, <form>, <head>Page на UserControl совмещенного кода
и файл имеет исполнимый код в блоке скриптов, то нужно в
Control обязательно
добавить атрибут ClassName =" имя_файла_или_любое_имя ".
Он извещает ASP.NET, что код, который нужно
компилировать, находится в том же файле в дескрипторах <script>.
Без этой информации файл компилироваться не будетИспользуя перечисленные шаги, создадим пользовательские элементы
управления, которые реализуют пользовательский интерфейс и
функциональность, использованную нами при выполнении предыдущих
упражнений в тестовых страницах. Из этих тестовых страниц мы
их и переделаем. Получится так, что пользовательский элемент
управления будет включен в тестовую страницу, а сама тестовая
страница будет превращена в пользовательский элемент и будет
динамически включаться по выбору из списка на исполнимую страницу DynamicUserControls.aspx в
зарезервированные -места.
В панели Solution Explore выделите при нажатой клавише Ctrl следующие файлыHeaderTest.aspxTimeDisplayTest.aspxLinkTableTest.aspxMyControlTest.aspx
Выполните
команду Copy затем Paste (на
верхнем узле проекта) контекстного меню
Присвойте
копиям те же самые имена, только с расширением .ascxHeaderTest.ascxTimeDisplayTest.ascxLinkTableTest.ascxMyControlTest.ascx
Откройте
новые файлы в дескрипторном режиме и замените @Page на @Control, все
остальные атрибуты бывшей @Page оставьте
прежними. Теперь это будут не страницы, а пользовательские
элементы управления. @Register с
ее атрибутами изменять не нужно
Удалить
из кода все дескрипторы <html>, <body>, <form>, <head> и
закрывающие их дескрипторыВ результате новые пользовательские элементы должны иметь следующий код интерфейсной части
| HeaderTest.ascx |
|---|
<%@ Control AutoEventWireup="true" CodeFile="HeaderTest.ascx.cs"
Inherits="HeaderTest" Language="C#" %>
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
<myElem:Header ID="Header1" runat="server" />
|
| TimeDisplayTest.ascx |
<%@ Control Language="C#" %>
<%@ Register Src="TimeDisplay.ascx" TagName="TimeDisplay" TagPrefix="uc1" %>
<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" />
|
| LinkTableTest.ascx |
<%@ Control AutoEventWireup="true" CodeFile="LinkTableTest.ascx.cs"
Inherits="LinkTableTest" Language="C#" %>
<%@ Register Src="LinkTable.ascx" TagName="LinkTable" TagPrefix="uc1" %>
<uc1:LinkTable ID="LinkTable1" runat="server"
OnLinkClicked="LinkTable1_LinkClicked" />
<br />
<asp:Label ID="lblInfo" runat="server"></asp:Label>
|
| MyControlTest.ascx |
<%@ Control AutoEventWireup="true" CodeFile="MyControlTest.ascx.cs"
Inherits="MyControlTest" Language="C#" %>
<%@ Register Src="MyControl.ascx" TagName="MyControl" TagPrefix="uc1" %>
<uc1:MyControl ID="MyControl1" runat="server" />
<br />
<br />
<asp:RadioButtonList ID="RadioButtonList1" runat="server"
OnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged"
RepeatDirection="Horizontal">
<asp:ListItem Value="Red">Красный</asp:ListItem>
<asp:ListItem Value="Green">Зеленый</asp:ListItem>
<asp:ListItem Value="Blue">Синий</asp:ListItem>
</asp:RadioButtonList>
<br />
<input id="Submit1" type="submit" value="submit" />
|
Для
новых файлов *.ascx откройте файлы скрытого
кода *.ascx.cs и замените в объявлении
класса имя System.Web.UI.Page " на
" System.Web.UI. UserControl "Остальной
код классов останется прежним. Мы закончили выполнение
упражнения. Код исполнимой страницы DynamicUserControls.aspx при очередной загрузке будет программно создавать свои пользовательские
элементы управления для каждого контейнера и
размещать их в элементах .
Выполните
страницу DynamicUserControls.aspx и испытайте
ее работуРезультат будет примерно таким


Файлы к лабораторной работе Вы можете скачать здесь.
Пользовательские элементы управления (user control) разрабатывает сам программист в тех случаях, когда стандартные элементы управления его не удовлетворяют или он разработал удачный вариант кода. Такой элемент управления можно многократно использовать на многих страницах и последующие его модернизации немедленно будут отображаться на всех страницах, где он используется. Часто пользовательские элементы управления применяются для стандартизации (единообразия) интерфейса страниц, например, оформления верхнего и нижнего колонтитулов.
Пользовательский элемент управления представляет собой небольшую часть страницы, которая может содержать статический HTML-код и стандартные элементы управления. В пользовательских элементах управления можно предусмотреть свои свойства, методы и события. Пользовательские блоки кода могут многократно использоваться на разных страницах, но только одного сайта. Для применения в другом сайте его либо нужно скопировать в этот сайт, либо создавать библиотечные специальные серверные элементы наподобие стандартных ( custom server control ).
Файл пользовательского элемента управления может содержать
то же самое, что и файл обычной исполнимой страницы, включая
файл поддержки .cs,
статический HTML-код, стандартные элементы управления. Они
получают те же самые события, что и объект Page,
имеют доступ к таким важным объектам-свойствам, как Application, , , . Но есть
и существенные отличия:
.aspx, пользовательские элементы
управления должны храниться в файлах с расширением .ascxPage,
а объект пользовательского элемента управления производится
от класса UserControl .
Но учитывая, что оба класса ( Page и UserConrol )
наследуют класс TemplateControl, они преобретают много одинаковых
свойств и событий от этого класса
.ascx, а должна это делать через .aspx, в который внедряется
ссылка на файл .ascx<html>, <head>, <body>, <form>@Page файл пользовательского
элемента управления содержит @ControlСреда проектирования позволяет видеть внедренный в страницу
пользовательский элемент управления на поверхности конструктора Design страницы.
Заготовку пользовательского
элемента управления легко создает мастер среды проектирования.
Создадим пользовательский элемент управления, который будет
представлять собой простой
Создайте
новый пустой сайт командой File/New/Website с
именем UserControls 
Выполните
команду Website/Add New Item, выберите шаблон Web
User Control и задайте имя Header .ascx
Созданный мастером файл содержит
только одну строку
<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="Header.ascx.cs" Inherits="Header" %>
Пользовательский элемент управления редактируется в оболочке
точно также, как и обычная страница. Файл кодовой части .ascx.cs содержит
тот же код, что и для обычной страницы. В данном упражнении
он нам не нужен, поэтому ничего в нем делать не будем.
Поместите
в интерфейсную часть Header .ascx ниже @Control следующую
HTML-разметку<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="Header.ascx.cs" Inherits="Header" %>
<table bgcolor="blue">
<tr>
<td>
<font color="yellow" face="Vernada, Arial" size="6">
<strong>Тестовая страница User Control</strong>
</font>
</td>
</tr>
<tr>
<td align="right">
<font color="white">
<strong>Время создания: апрель 2009г copy; Все права защищены</strong>
</font>
</td>
</tr>
</table>
Эта разметка даст такое визуальное представление
Тестовая страница User Control
Время создания: апрель 2009г $$\copyright$$ Все права защищеныВсе, что будет находиться на одной странице .ascx,
будет представлять собой один завершенный пользовательский
элемент управления, который мы можем вставлять в любое место
исполнимой страницы.
Продолжим выполнение нашего упражнения. Код пользовательского
элемента управления предполагает его использование на одной
или нескольких исполнимых страницах .aspx,
поэтому создадим такую страницу.
Добавьте
командой Website/Add New Item новую страницу с именем HeaderTest.aspx для
внедрения в нее пользовательского элемента управленияЧтобы применить пользовательский элемент управления на странице, нужно выполнить следующие шаги:
@Register ,
помещенной в начале страницы после @Page, нужно
сообщить ASP.NET,
что где-то на странице есть ссылка на пользовательский элемент
управления<form> дескриптор
пользовательского элемента
Добавьте
вручную на страницу HeaderTest.aspx сразу
после @Page следующую строку регистрации<%@ Register Src="Header.ascx" TagPrefix="myElem"
TagName="Header" %>
Мы знаем, что для различения типа библиотечных элементов управления
в начале их дескрипторного представления используется конструкция <префикс : тип_элемента атрибуты...
/>,
например
<asp:TextBox ID="TextBox1" runat="server" />
Здесь asp играет
роль префикса TagPrefix (или
условного пространства имен), а TextBox -
типа элемента управления TagName.
Директива регистрации связывает вместе файл с кодом, имя и
префикс для классификации и позволяет при размещении элемента
на странице применять стандартный синтаксис дескрипторного
представления серверных элементов. Значения myElem и мы
задали произвольно, но далее эти значения на странице мы должны
строго соблюдать, а значение атрибута Src (Source -
источник) означает имя подключаемого файла с пользовательским
элементом управления.
В зарегистрированных обозначениях пользовательского элемента
управления синтаксис его подключения к странице HeaderTest.aspx будет
представлен парным дескриптором
<myElem:Header ID="Header1" runat="server" ></myElem:Header>
или самозакрывающимся дескриптором
<myElem:Header ID="Header1" runat="server" />
Поместите
вручную внутрь дескриптора <form> код
объявления на странице пользовательского элемента управления,
чтобы в результате пользовательская страница HeaderTest.aspx стала
иметь следующую XML-разметку<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="HeaderTest.aspx.cs" Inherits="HeaderTest" %>
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<myElem:Header ID="Header1" runat="server" />
</div>
</form>
</body>
</html>
Обратите внимание, что при добавлении регистрации элемента
управления на страницу подсказчик кода услужливо
предоставляет всю необходимую информацию для правильного написания
синтаксической конструкции.
Мы рассмотрели способ, которым к странице подключается файл
с любым внешним кодом. Этот код реально может быть любой сложности,
включая все мыслимые элементы управления. Обратите внимание,
что код файла не
содержит ссылок на другие страницы и готов использоваться на
любой странице как дополнение.
На файл пользовательского элемента, в свою очередь, может быть помещен другой пользовательский элемент, разработанный ранее. В таком случае этот подключаемый элемент нужно зарегистрировать на родителе точно так же, как это делается при подключении к конечной странице.
Запустите
тестовую страницу на выполнение, должен получиться такой
результат
До сих пор мы работали только с интерфейсной частью и не использовали код застраничного файла, хотя и создали его. Но чаще всего это нужно делать, чтобы добавить функциональность, которая может понадобиться клиенту.
Воспользуемся стандартным
элементом управления LinkButton, который
будет снимать с
Вызовите
мастер для создания пользовательского элемента управления,
выполнив команду 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" />
В коде мы добавили свою функцию 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>
Выполните
страницу, которая на клиенте будет такой
При каждом щелчке пользователя на ссылке-кнопке броузер будет
инициировать обратную отсылку на сервер, разработанная страница
при исполнении снимет с
Что мы только что сделали в нашем упражнении. Мы код, который можно исполнить одной страницей, разделили на две части, выделив типовую часть в отдельный файл, который назвали пользовательским элементом управления. Это напоминает прием упаковки кода в отдельную функцию. Выполним обратную операцию и сосредоточим весь код на одной исполнимой странице.
Добавьте
к проекту страницу 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>
Выполните
страницу и убедитесь, что выдается точно такой же результат,
как и в случае с промежуточным файлом 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" />
Измените
код тестовой страницы 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>
Тестовая страница является клиентом пользовательского элемента
управления. Именно в дескрипторе элемента на клиенте мы определяем
значение добавленного свойства Format как атрибут этого дескриптора.
Обратите внимание, что в подсказчике кода , применяемом
при редактировании дескриптора пользовательского элемента управления,
появилось новое свойство 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();
}
то мы бы всегда получали результат варианта без форматирования, а именно

Иногда приходится создавать специальные классы для организации
взаимодействия между пользовательским элементом
управления и Web-страницей. Создадим
сложный пользовательский элемент управления LinkTable,
предназначенный для генерирования набора гиперссылок в форматированной
таблице. Для удобства часть кода разместим в отдельном самостоятельном
классе LinkTableItem.
Создайте
страницу Web Form с раздельным кодом и именем LinkTableTest.aspx
Сделайте
эту страницу стартовой
Добавьте
к проекту новую папку с зарезервированным именем App_Code.
Для этого в панели Add ASP.NET Folder /App_Code
Через
контекстное меню на созданной папке App_Code выполните
команду Add
New Item и добавьте к приложению новый класс C#
с именем LinkTableItem.cs
Этот класс в своих полях будет хранить информацию, необходимую пользовательскому элементу управления, а через свойства осуществлять доступ к ней.
Заполните
вспомогательный класс в файле LinkTableItem.cs следующим
кодом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;
/// <summary>
/// Вспомогательный класс LinkTableItem
/// </summary>
public class LinkTableItem
{
// Хранимые поля закрытого типа
private string text, url;
// Конструктор по умолчанию
public LinkTableItem()
{
// Пустой конструктор по умолчанию обязателен
// поскольку есть общий конструктор
}
// Общий конструктор
public LinkTableItem(string text, string url)
{
// Внутренним полям присваиваются значения,
// переданные из родительского объекта
this.text = text;
this.url = url;
}
// Определение свойств доступа к внутренним полям
public string Text
{
get { return text; }
set { text = value; }
}
public string Url
{
get { return url; }
set { url = value; }
}
}
Теперь нужно создать пользовательский элемент, который будет управлять этим вспомогательным классом.
Создайте
заготовку пользовательского элемента управления с
отделенным кодом и именем LinkTable.
Для этого выполните команду Add New Item,
вызвав контекстное меню для корневого узла проекта в панели Solution
Explorer и установив шаблон Web User Control 
Поместите
в таблицу пользовательского элемента следующие стандартные
компоненты:Table из вкладки HTML, который будет форматировать
размещение стандартных элементов управленияLabel из
вкладки Standard в верхнюю ячейку
таблицы, который будет определять заголовок набора ссылокImage из вкладки HTML, определяющий рисунок маркера
ссылокDataList из вкладки Data в нижнюю ячейку
таблицыHyperLink из вкладки Standard
Настройте
интерфейсную часть пользовательского элемента управления
так<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="LinkTable.ascx.cs" Inherits="LinkTable" %>
<table cellpadding="2">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small"
ForeColor="#C00000">
<%--Здесь будет заголовок--%>
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img alt="маркер" height="13" src="32_27.gif" width="25">
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
Text='<%# DataBinder.Eval(Container.DataItem, "Text") %>'>
</asp:HyperLink>
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
Дескриптор <img> для красоты определяет
маркер, который вы можете сами изготовить размером 25x13 или
взять из прилагаемого каталога Source (файл 32_27.gif,
который имеет изображение
).
Атрибут alt задает альтернативную надпись
в поле рисунка, если последний не будет найден.
Вызовите
для корневого узла проекта контекстное меню и командой Add Existing Item скопируйте
из прилагаемого каталога Source файл 32_27.gif Теперь пришла пора программно расширить функциональность пользовательского
элемента управления LinkTable.
Вызовите
на редактирование файл LinkTable.ascx.cs и
заполните его следующим кодомusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 LinkTable : System.Web.UI.UserControl
{
public string Title
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
private LinkTableItem[] items;
public LinkTableItem[] Items
{
get { return items; }
set
{
items = value;
// Обновляем сетку
listContent.DataSource = items;
listContent.DataBind();
}
}
}
Разработка пользовательского элемента управления закончена.
Теперь нужно поместить его на пользовательскую тестовую страницу LinkTableTest.aspx,
которую мы создали в самом начале выполнения этого упражнения
и сделали ее стартовой.
Выполните
команду Window/Close All Documents, чтобы закрыть все окна
редактирования
Откройте
через панель Solution Explorer на редактирование
файл LinkTableTest.aspx в
режиме Design и перетащите на форму из этой
панели узел LinkTable.ascx пользовательского
элемента управленияДескрипторное представление тестовой страницы с зарегистрированным на ней пользовательским элементом управления имеет такой вид
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="LinkTableTest.aspx.cs" Inherits="LinkTableTest" %>
<%@ Register Src="LinkTable.ascx" TagName="LinkTable" TagPrefix="uc1" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Тестовая страница сложного элемента управления</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:LinkTable ID="LinkTable1" runat="server" />
</div>
</form>
</body>
</html>
Откройте
на редактирование застраничный файл LinkTableTest.aspx.cs и
заполните его следующим кодомusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 LinkTableTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Формируем заголовок списка
LinkTable1.Title = "Список жизненно важных гиперссылок";
// Создаем список элементов - гиперссылок
LinkTableItem[] items = new LinkTableItem[3];
items[0] = new LinkTableItem("Ссылка №1 к Большому Биллу",
"http://www.microsoft.com");
items[1] = new LinkTableItem("Ссылка №2 к автошколе \"Диалог-Сервис\"",
"http://www.dialog-service.net");
items[2] = new LinkTableItem("Ссылка №3 к затычке JavaScript",
"javascript:void(0)");
LinkTable1.Items = items;
}
}
Запустите
приложение и убедитесь, что генерируемый пользовательским
элементом управления набор гиперссылок работает исправно
Событие - это встроенный механизм C#, с помощью которого автоматически обеспечивается уведомление зарегистрированных объектов о необходимости выполнения ими какого-то действия. Объект предоставляет свои методы-обработчики для реагирования на возникновение определенного события. В этом случае говорят, что объект подписался на некоторое событие. Такой механизм позволяет отдельным объектам обмениваться сообщениями и реагировать на них.
Технически событие представляет собой некую адресную переменную, ссылающуюся на экземпляр класса, поддерживающего событие. Если значение этой ссылки равно null, то событие не произошло, поскольку нет соответствующего объекта. Один объект генерирует событие (создает экземпляр) и посылает уведомление через канал сообщений операционной системы. Другие, подписанные на это событие объекты приложения, получают это сообщение вместе с дополнительной информацией и запускают соответствующие обработчики, предварительно передав им дополнительную информацию в качестве аргументов.
Для объявления адресной переменной события используются делегаты.
С помощью конструктора
На предыдущем шаге мы с помощью вспомогательного класса LinkTableItem могли добавлять в классе
пользовательского элемента управления LinkTableTest новые
гиперссылки типа asp: к элементу asp:.
По щелчку клиента на одной из гиперссылок он безусловно направлялся
по указанному адресу. Теперь же мы хотим перехватывать и распознавать
щелчок на любой гиперссылке для контроля за действиями пользователя.
Сейчас мы не будем оценивать полномочия пользователя, просто
распознаем гиперссылку и выведем ее на экран.
Ранее в дескрипторном представлении пользовательского элемента
управления мы применяли стандартный элемент asp:.
Если посмотреть на класс этого элемента System.Web.UI. через
панель Object
,
то можно увидеть, что он не имеет никаких событий

С другой стороны, класс LinkButton имеет два события, которые
генерирует элемент при выборе пользователя

Эти события мы и будем перехватывать в нашем элементе управления.
Измените
в шаблоне <ItemTemplate> дескрипторного
представления файла LinkTable.ascx имя элемента HyperLink на LinkButton и
имя атрибута NavigateUrl на CommandArgument,
после чего файл должен стать таким<%@ Control Language="C#" AutoEventWireup="true"
CodeFile="LinkTable.ascx.cs" Inherits="LinkTable" %>
<table cellpadding="2">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small"
ForeColor="#C00000">
<%--Здесь будет заголовок--%>
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img alt="маркер" height="13" src="32_27.gif" width="25">
<asp:LinkButton ID="HyperLink1" runat="server"
CommandArgument='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
Text='<%# DataBinder.Eval(Container.DataItem, "Text") %>'>
</asp:LinkButton>
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
Мы хотим создать событие с именем LinkClicked.
Для распознавания выбранного пункта списка нам вместе с будущим
событием LinkCliked нужно
будет передавать информацию о значениях свойств Text и Url,
которые мы определили ранее во вспомогательном классе LinkTableItem.cs.
Затем в обработчике события LinkClicked мы
распознаем эту информацию и выведем ее на экран.
Напрямую экземпляр класса LinkTableItem.cs в
аргументах события передавать нельзя - не тот тип, поэтому
упакуем его в класс LinkTableEventArgs,
который будет наследником библиотечного класса System.EventArgs.
Объявим также
Откройте
файл LinkTable.ascx.cs пользовательского
элемента управления и добавьте в него объявление нового класса
и using System;
using System.Data;
using System.Configuration;
using System.Collections;
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 LinkTable : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public string Title
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
private LinkTableItem[] items;
public LinkTableItem[] Items
{
get { return items; }
set
{
items = value;
// Обновляем сетку
listContent.DataSource = items;
listContent.DataBind();
}
}
}
// Объявляем делегат будущего события LinkClicked,
// который определит сигнатуру события и обработчика
public delegate void LinkClickedEventHandler(object sender, LinkTableEventArgs e);
// Класс-упаковка экземпляра LinkTableItem для
// передачи с событием в качестве аргумента
public class LinkTableEventArgs : EventArgs
{
// Конструктор
public LinkTableEventArgs(LinkTableItem item)
{
selectedItem = item;
}
// Внутреннее поле будет хранить объект гиперссылки
// и контролируется свойством "только для чтения"
private LinkTableItem selectedItem;
public LinkTableItem SelectedItem
{
get { return selectedItem; }
}
// Внутренне поле хранит флаг отмены, переданный сгенерировавшим
// событие классом-источником для обработчика класса-приемника
private bool cancel = false;// Инициализируется при создании
public bool Cancel
{
get { return cancel; }
set { cancel = value; }
}
}
Таким образом, мы объявили класс для упаковки передаваемой
в событии информации. мы также объявили LinkClicked отправит
эту информацию в канал сообщений Windows.
Конечно же, этим должен заниматься класс LinkTable поддержки
пользовательского элемента управления.
Откройте
на редактирование файл LinkTable.ascx в
режиме Design
Выделите
пользовательский элемент управления listContent и
в панели Properties двойным щелчком на
поле события ItemCommand создайте обработчик
с именем по умолчанию
Добавьте
в класс LinkTable и созданный обработчик
стандартного события ItemCommand следующий кодpublic partial class LinkTable : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
public string Title
{
get { return lblTitle.Text; }
set { lblTitle.Text = value; }
}
private LinkTableItem[] items;
public LinkTableItem[] Items
{
get { return items; }
set
{
items = value;
// Обновляем сетку
listContent.DataSource = items;
listContent.DataBind();
}
}
// Объявляем в классе наше событие LinkClicked
// с помощью ранее созданного глобального делегата
public event LinkClickedEventHandler LinkClicked;
protected void listContent_ItemCommand(object source, DataListCommandEventArgs e)
{
if (LinkClicked != null)
{
// Выделяем объект ссылки, на которой был выполнен щелчок
LinkButton link = (LinkButton)e.Item.Controls[1];
// Выделяем нужные свойства Text и Url через атрибуты
// дескриптора элемента LinkButton и сохраняем их
// в экземпляре вспомогательного класса
LinkTableItem item = new LinkTableItem(link.Text, link.CommandArgument);
// Передаем ссылку на сохраненные свойства в класс упаковки аргументов
LinkTableEventArgs args = new LinkTableEventArgs(item);
// Генерируем событие
LinkClicked(this, args);
// Пускаем клиента по ссылке, если класс-получатель не запретил
if (args.Cancel != true)
{
Response.Redirect(item.Url);
}
}
}
}
Теперь событие LinkClicked будет возникать
всякий раз, когда пользователь щелкнет на гиперссылке пользовательского
элемента управления. Классом-получателем этого события определим
нашу тестовую страницу. Именно в ней мы создадим функцию-обработчик,
которая распакует переданные событием аргументы и выведет полученную
информацию на экран. Проверку существования события мы выполняем
на случай, чтобы наверняка предотвратить генерацию системного
исключения, если не существует ни одного обработчика.
Учитывая, что в режиме проектирования оболочка поддерживает
автоматическое создание обработчиков через панель Properties только
для событий библиотечных классов, создадим заготовку обработчика
вручную. При этом нужно соблюсти оболочки
нам помогает.
Откройте
на редактирование файл LinkTableTest.aspx.cs и
в конце обработчика события Page_Load() класса LinkTableTest начните
набирать LinkTable1, под которым
на тестовой странице у нас числится экземпляр зарегистрированного
на ней пользовательского элемента управления. Вы сразу увидите
реакцию подсказчика кода IntelliSense 
Нажав два раза клавишу Tab мы получим и
регистрацию события в классе-приемнике через глобального
LinkTable1.LinkClicked += new LinkClickedEventHandler(LinkTable1_LinkClicked);
Если выбрать второй способ, тогда нужно в дескрипторном представлении
пользовательского элемента добавить атрибут OnLinkClicked="LinkTable1_LinkClicked",
чтобы привязать к событию созданный обработчик (обратите внимание,
что имя атрибута формируется из имени события и префикса On ).
Но и в этом случае подсказчик кода нам тоже помогает

Выберем второй способ регистрации обработчика для события LinkClicked.
Уничтожте
регистрацию события в классе LinkTableTest,
скопируйте имя сгенерированного обработчика и добавьте его
в атрибут OnLinkClicked="LinkTable1_LinkClicked" дескриптора <uc1:LinkTable
ID="LinkTable1" runat="server" /> файла
тестовой страницы LinkTableTest.aspx
В режиме Design тестовой страницы разместите последней
текстовую метку asp:Label из вкладки Standard,
задайте ей имя lblInfo и
очистите поле ее свойства Text (либо
удалите одноименный атрибут в дескрипторе). В ней мы будем
отображать информацию о нажатой гиперссылке
Вернитесь
в файл LinkTest.aspx.cs и заполните обработчик такprotected void LinkTable1_LinkClicked(object sender, LinkTableEventArgs e)
{
// Ищем подстроку в вызывающей строке
if (e.SelectedItem.Text.IndexOf("Диалог-Сервис") > 0)
{
e.Cancel = false;// Пропустить
}
else
{
e.Cancel = true; // Не пускаем дальше
lblInfo.Text = "Вы щелкнули " +
"\"" + e.SelectedItem.Text + "\".";
lblInfo.Text += " Извините, но Вам не разрешено идти на " +
e.SelectedItem.Url + "!!!";
}
}
Запустите
тестовую страницу LinkTableTest.aspx и полюбуйтесь
на свою работу
Web-страница, которая содержит интегрированный в нее пользовательский элемент управления, не может без дополнительных приемов получать доступ к компонентам этого элемента: к его методам, событиям, свойствам. Такое положение является обоснованным, чтобы случайно в Web-странице не внести нежелательные изменения в ее дочерний элемент.
Но учитывая, что сам пользовательский элемент имеет доступ к своим компонентам, а страница имеет доступ к пользовательскому элементу, это правило можно обойти. Для этого существует два способа:
В пользовательский элемент вводят промежуточные
свойства или private упаковывают
в функции доступа public, которые сами
видят эти переменные, а их, в свою очередь, видят клиенты
этого класса.
Пусть, например, пользовательский элемент управления MyControl1 как
объект порождается классом MyControl и в качестве
одного из компонентов содержит в себе объект Label1 библиотечного
класса System.Web.UI.. Класс Label наследует от System.Web.UI. свойство BackColor, которое, в свою очередь, имеет
тип System.Drawing.Color. Напрямую из Web-страницы
нельзя установить новое значение свойства BackColor компонента Label1 пользовательского элемента. Но можно
открыть доступ к этому свойству для Web-страницы, введя промежуточное
свойство BackColor (или
с другим именем) в классе самого пользовательского элемента.
Сказанное схематично изображено на рисунке

Выполним это на практике.
Создайте
заготовку пользовательского элемента Web User Control с
именем MyControl.ascx с
раздельным кодом (флажок Place code in separate file мастера
включен)
Перейдите
в режим Design редактора заготовки и
поместите на нее из вкладки Standard элемент Label с
именем Label1
В панели Solution Explorer откройте файл отделенного
кода MyControl.ascx.cs,
удалите из класса MyControl заготовку
обработчика Page_Load() за ненадобностью
и дополните using System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControl : System.Web.UI.UserControl
{
public string Text
{
get { return Label1.Text; }
set { Label1.Text = value; }
}
public System.Drawing.Color BackColor
{
get { return Label1.BackColor; }
set { Label1.BackColor = value; }
}
public System.Drawing.Color ForeColor
{
get { return Label1.ForeColor; }
set { Label1.ForeColor = value; }
}
}
Здесь для свойств доступа мы использовали имена точно такие,
как у прямых свойств компонента Label1.
Но это не обязательно, можно использовать любые имена.
Создайте
пользовательскую тестовую страницу с раздельным кодом под
именем MyControlTest.aspx и
переведите ее в режим редактирования Design
Из
панели Solution Explorer из дерева файлов
приложения перенесите на тестовую страницу узел MyControl.ascx.
Убедитесь, что экземпляр пользовательского элемента управления
зарегистрировался на тестовой странице под именем MyControl1
Попробуйте
выделить добавленный пользовательский элемент управления
и убедитесь, что он не выделяется и добавленные нами свойства
не видны в панели Properties Если пытаться устанавливать начальные настройки пользовательского элемента через атрибуты его дескриптора, то подсказчик кода сообщит, что это возможно, поскольку введенные нами вспомогательные свойства доступны из клиентской страницы

Аналогичным образом, введенные свойства доступны и из программного кода клиентской страницы через имя экземпляра пользовательского элемента, в чем мы сейчас и убедимся на практике.
Поместите
на страницу под пользовательским элементом управления компонент RadioButtonList из
вкладки Standard и
убедитесь, что он имеет ID="RadioButtonList1"
Через
коллекцию Items элемента RadioButtonList1 задайте
три радиокнопки с такими свойствами
Установите
свойство RepeatDirection элемента RadioButtonList1 в
значение Horozontal
Выделите
компонент RadioButtonList1 и через панель Properties создайте обработчик для его события SelectedIndexChanged
Под
списком радиокнопок поместите компонент Input (Submit) из
вкладки HTMLДескрипторное представление страницы будет иметь вид
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="MyControlTest.aspx.cs"
Inherits="MyControlTest" %>
<%@ Register Src="MyControl.ascx" TagName="MyControl" TagPrefix="uc1" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<uc1:MyControl ID="MyControl1" runat="server" />
<br />
<br />
<asp:RadioButtonList ID="RadioButtonList1" runat="server"
RepeatDirection="Horizontal"
OnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged">
<asp:ListItem Value="Red">Красный</asp:ListItem>
<asp:ListItem Value="Green">Зеленый</asp:ListItem>
<asp:ListItem Value="Blue">Синий</asp:ListItem>
</asp:RadioButtonList></div>
<br />
<input id="Submit1" type="submit" value="submit" />
</form>
</body>
</html>
Мы хотим, чтобы на клиенте при щелчке на кнопке Submit выполнялась
обратная отсылка на сервер, где код страницы через
введенные нами в класс пользовательского элемента управления
дополнительные свойства менял бы настройку элемента Label1.
Этот код смены настройки нужно поместить в созданный нами обработчик
радиокнопок, чтобы он срабатывал каждый раз, когда получит
обратную отсылку с требованием пользователя выполнить новые
настройки. В результате элемент Label1 сгенерирует
нужный HTML-код
и отошлет его клиенту.
Заполните
обработчик RadioButtonList1_SelectedIndexChanged() страницы в файле MyControlTest.aspx.cs следующим кодомusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlTest : System.Web.UI.Page
{
protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)
{
int index = RadioButtonList1.SelectedIndex;
switch (index)
{
case 0:
MyControl1.ForeColor = System.Drawing.Color.White;
MyControl1.BackColor = System.Drawing.Color.Red;
break;
case 1:
MyControl1.ForeColor = System.Drawing.Color.Aqua;
MyControl1.BackColor = System.Drawing.Color.Green;
break;
case 2:
MyControl1.ForeColor = System.Drawing.Color.Yellow;
MyControl1.BackColor = System.Drawing.Color.Blue;
break;
}
if(index != -1)
MyControl1.Text = RadioButtonList1.Items[index].Value;
}
}
Выполните
страницу и убедитесь, что при щелчке на
кнопке код исполнимой страницы меняет свойства компонента Label1 через
добавленные нами дополнительные глобальные свойства
Есть еще один способ обеспечить доступ к компонентам, интегрированным
в пользовательский элемент управления, это добавить в пользовательский
элемент по дополнительному свойству, возвращающее ссылку на
каждый компонент. При этом нужно использовать только get -аксессоры,
поскольку адреса компонентов менять нельзя. В дальнейшем через
это свойство-ссылку, доступную из страницы, можно
обратиться к любым членам раскрытого таким образом компонента,
входящего в состав пользовательского элемента.
Скопируйте
через панель Solution Explorer , как это
мы делали ранее, файл исполнимой страницы MyControlTest.aspx и
файл пользовательского элемента управления MyControl.ascx
Присвойте
копиям новые имена MyControlTestExt.aspx и MyControlExt.ascx соответственно
(сопровождающие застраничные кодовые файлы оболочка переименует
автоматически)
Сделайте
страницу MyControlTestExt.aspx стартовой,
выполнив на ее узле в панели Solution Explorer команду Set
As Start Page
Измените
в файле MyControlTestExt.aspx значение
параметра Inherits на Inherits="MyControlTestExt" @Page
Измените
параметр Src MyControlTestExt.aspx<%@
Откройте
файл скрытого кода MyControlExt.ascx.cs и
измените в нем класс MyControl, чтобы он выглядел такusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlExt : System.Web.UI.UserControl
{
// Раскрываем весь компонент Label1
// Имя свойства InnerLabel1 выбрали произвольно
// Используется только get-аксессор
public Label InnerLabel1
{
get { return Label1; }
}
}
Скорректируйте
в файле MyControlExt.ascx атрибут Control так Inherits="MyControlExt"
Откройте
файл MyControlTestExt.aspx.cs скрытого кода
тестовой страницы и отредактируйте его для доступа
к прямым свойствам компонента Label1 с использованием
созданного адреса InnerLabel1using System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlTestExt : System.Web.UI.Page
{
protected void RadioButtonList1_SelectedIndexChanged(object sender, EventArgs e)
{
int index = RadioButtonList1.SelectedIndex;
// Доступ к прямым свойствам компонента Label1 выполняем
// через ссылку на этот компонент в родителе MyControl1
switch (index)
{
case 0:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.White;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Red;
break;
case 1:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Aqua;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Green;
break;
case 2:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Yellow;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Blue;
break;
}
if(index != -1)
MyControl1.InnerLabel1.Text = RadioButtonList1.Items[index].Value;
}
}
Выполните
страницу и убедитесь, что получился тот же самый результат,
что и в предыдущем примере при реализации первого способа
Какой способ выбрать - решает программист!
На протяжении этой темы мы рассматривали вопрос создания пользовательского элемента управления в режиме проектирования и последующее управление им в программном режиме. Но может потребоваться на странице подгружать и настраивать пользовательский элемент управления динамически ("на лету").
Для динамического создания пользовательского элемента управления ребуется выполнить следующие шаги:
Page.Load экземпляр
класса пользовательского элемента управления, заранее подготовленного
в файлах *.ascx и *.ascx.cs.
Создание и регистрация экземпляра пользовательского элемента
в коде исполнимой страницы осуществляется Page.LoadControl().PlaceHolder место
размещения для точного ID пользовательского
элемента управления, особенно, когда создается несколько
экземпляров одного и того же элемента. Это может понадобиться
для однозначной идентификации элемента в коде страницы при
поиске ссылки на экземпляр, выполняемом с помощью статического
метода Page.FindControl(),
который как раз использует значение идентификатора ID.Есть некоторая специфика динамического создания пользовательского
элемента управления по сравнению с библиотечным компонентом.
Нельзя создать пользовательский элемент напрямую, как это делается
с библиотечным элементом управления через *.ascx.cs,
но и дескрипторной части файла *.ascx. Поэтому
на ASP.NET объединением
этих двух частей на этапе выполнения.
Скопируйте
через панель Solution Explorer , как это
мы делали ранее, файл тестовой страницы MyControlTestExt.aspx и
файл пользовательского элемента управления MyControlExt.ascx
Присвойте
копиям новые имена MyControlDynamicTest.aspx и MyControlDynamic.ascx соответственно
(застраничные файлы оболочка переименует
автоматически)
Сделайте
страницу MyControlDynamicTest.aspx стартовой,
выполнив на ее узле в панели Solution Explorer команду Set
As Start Page
Откройте
файл MyControlDynamic.ascx в режиме Source и исправьте в директиве @Control атрибут подключаемого класса
так Inherits =" MyControlDynamic "
Откройте
застраничный файл MyControlDynamic.ascx.cs и измените имя
класса на MyControlDynamic
Закройте
все предыдущие редактируемые документы командой меню Window/Close
All Documents
Откройте
на редактирование страницу MyControlDynamicTest.aspx в
режиме Design, удалите
наш пользовательский элемент управления Label1 и
поместите на его место из вкладки Standard стандартный
элемент управления PlaceHolder
Перейдите
в файле MyControlDynamicTest.aspx в режим Source редактора
страницы, откорректируйте атрибут Inherits =" MyControlDynamicTest " и
удалите полностью старый код <%@
В этом
же файле MyControlDynamicTest.aspx в
режиме Source удалите
из дескриптора <asp:RadioButtonList> атрибут
регистрации обработчикаOnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged"
На данном этапе страница в дескрипторном представлении будет такой
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="MyControlDynamicTest.aspx.cs"
Inherits="MyControlDynamicTest" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:PlaceHolder ID="PlaceHolder1" runat="server" />
<br />
<br />
<asp:RadioButtonList ID="RadioButtonList1" runat="server"
RepeatDirection="Horizontal">
<asp:ListItem Value="Red">Красный</asp:ListItem>
<asp:ListItem Value="Green">Зеленый</asp:ListItem>
<asp:ListItem Value="Blue">Синий</asp:ListItem>
</asp:RadioButtonList>
<br />
<input id="Submit1" type="submit" value="submit" />
</div>
</form>
</body>
</html>
Теперь пользовательский элемент управления на странице
не существует, а вместо него вставлен заменитель пустого
места PlaceHolder1.
Далее мы программно должны создать пользовательский элемент,
добавить ссылку на него к странице, а затем можно управлять
свойствами его компонентов.
Откройте
на редактирование застраничный MyControlDynamicTest.aspx.cs,
выполнив команду контекстного меню View Code редактора
Измените
код обработчика Page_Load(), чтобы он
стал такимusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 MyControlDynamicTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Создаем экземпляр класса поддержки
// пользовательского элемента управления
MyControlDynamic MyControl1 = (MyControlDynamic)
Page.LoadControl("MyControlDynamic.ascx");
// Добавляем объект в зарезервированное место страницы
PlaceHolder1.Controls.Add(MyControl1);
int index = RadioButtonList1.SelectedIndex;
// Доступ к прямым свойствам компонента Label1 выполняем
// через ссылку на этот компонент в родителе MyControl1
switch (index)
{
case 0:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.White;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Red;
break;
case 1:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Aqua;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Green;
break;
case 2:
MyControl1.InnerLabel1.ForeColor = System.Drawing.Color.Yellow;
MyControl1.InnerLabel1.BackColor = System.Drawing.Color.Blue;
break;
}
if(index != -1)
MyControl1.InnerLabel1.Text = RadioButtonList1.Items[index].Value;
}
}
Обратите внимание, что при наборе кода создания пользовательского
элемента в нам не помогает,
потому что страница не знает, что где-то в файле MyControlDynamic.ascx существует
класс MyControl.
Запустите
страницу MyControlDynamicTest.aspx на выполнение
и убедитесь в работоспособности результата, как будто-бы
пользовательский элемент был помещен на исполнимую страницу
в декларативном режиме
Итак, мы разработали несколько пользовательских элементов управления:
Header .ascx - TimeDisplay.ascx - кнопка-ссылка, возвращающая неформатированную
и форматированную дату-времяLinkTable.ascx - список гиперссылок с
предварительным анализом выбора пользователя (для этого создали
свое событие)MyControl.ascx - с применением промежуточных средств доступа
к настройкам внутренних компонентовMyControlExt.ascx - с созданием общего свойства-ссылки
на встроенный компонент для доступа к любым его членамMyControlDynamic.ascx - то же самое, что и MyControlExt.ascx,
только применяли способ динамической загрузки пользовательского
элемента на тестовую страницуДля каждого из этих элементов управления разрабатывалась своя тестовая страница, на которую элемент управления помещался декларативно. Только в последнем случае мы сам пользовательский элемент не изменяли, но на тестовой странице создавали его динамически (программно).
В этом упражнении рассмотрим вопрос, когда на одну страницу нужно поместить программно сразу несколько разных пользовательских элементов управления.
Создайте
новую страницу DynamicUserControls.aspx с
раздельным кодом и сделайте ее стартовой
В раскрывающемся
списке панели Properties выберите элемент DOCUMENT и
задайте его свойству Title значение Портальные
каркасы
В режиме Design поместите с вкладки Standard элемент Panel и
присвойте ему имя Panel1 (оно
генерируется автоматически). Этот элемент будет служить
контейнером для других элементов управления, в том числе
и для пользовательского
Поместите
внутрь контейнера Panel1 друг за другом по вертикали стандартные
элементыDropDownList с автоматически сгенерированным
именем DropDownList1 -
для выбора загружаемого в контейнер пользовательского
элемента управленияPlaceHolder с автоматически сгенерированным
именем PlaceHolder1 -
для Label с автоматически сгенерированным
именем Label1 -
для отображения имени файла, из которого в контейнер загружен
пользовательский элемент управленияИнтерфейс страницы на

По большому счету нам в данном примере безразлично, какие
имена будут иметь экземпляры дочерних элементов. Однозначно
различать их в коде мы можем по найденным ссылкам. Ссылки,
в свою очередь, будем искать в именованном контейнере-панели
по типу дочернего элемента, поскольку помещенные нами элементы
имеют разный тип. Но сама оболочка Visual
Studio 2005 требует, чтобы на странице не было
декларативно объявляемых дескрипторов с одинаковыми значениями ID.
Проследите
в дескрипторном представлении страницы, чтобы ни один из
элементов, включая контейнер, не имел атрибутов Width и Height,
ограничивающих свободную Заметим, что контейнер Panel1, как
родитель, по умолчанию будет определять основные свойства своих
дочерних элементов, такие как
Ранее мы перечислили пользовательские элементы управления,
которые создали в данной работе. Выберем несколько их них для
динамического размещения. Имена этих элементов нужно занести
в список DropDownList1. Пусть это будут элементы:
Header .ascx - TimeDisplay.ascx - Кнопка 'время-дата'LinkTable.ascx - Контролируемый список
гиперссылокMyControl.ascx - С настройкой внутренних
компонентов
Выделите
объект DropDownList1 в
контейнере Place1 и заполните декларативно его
свойство Items так| Items[i] | Text | Value |
|---|---|---|
| Items[0] | (None) |
None |
| Items[1] | |
HeaderTest.ascx |
| Items[2] | Кнопка 'время-дата' |
TimeDisplayTest.ascx |
| Items[3] | Контролируемый
список гиперссылок |
LinkTableTest.ascx |
| Items[4] | С настройкой внутренних
компонентов |
MyControlTest.ascx |
В скрытом
поле Value мы указали имена файлов, которые
в будущем должны будем создать.
Установите
для элемента DropDownList1 его свойство AutoPostBack в значение True,
чтобы обеспечить постинг страницы при выборе пользователем
нужной опцииБудем считать, что один из трех стандартных элементов управления контейнера, а именно список, мы заполнили декларативно. Два других элемента контейнера будем заполнять программно.
Таким образом, один контейнер
мы почти настроили. Но мы хотим разместить на странице дополнительно
еще два таких контейнера, чтобы иметь возможность в каждый
из них программно загружать выбранные через список DropDownList1 пользовательские
элементы управления. При этом мы хотим убедиться, что они
работают независимо друг от друга и каждый делает то, что
должен путем реагирования на свои собственные события.
Через
раскрывающийся список панели Properties выделите
контейнер Panel1 и
настройте его свойства такBackColor = Web/Gainsboro -
BorderWidth = 1px -
толщина рамкиHorizontalAlign = Center -
расположение дочерних элементовBorderStyle = Ridge -
стиль контейнераEnableViewState =" False " -
отключить механизм сохранения состояния вида
В
режиме Design разрабатываемой страницы DynamicUserControls.aspx разместите
на ней по вертикали друг за другом еще две копии контейнера Place1 вместе
с его дочерними элементами и присвойте им имена Panel2, Panel3Мы закончили

Дескрипторное представление страницы должно быть таким
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="DynamicUserControls.aspx.cs" Inherits="DynamicUserControls" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Портальные каркасы</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel ID="Panel1" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
EnableViewState="False" HorizontalAlign="Center">
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True">
<asp:ListItem Value="None">(None)</asp:ListItem>
<asp:ListItem Value="HeaderTest.ascx">Верхний колонтитул</asp:ListItem>
<asp:ListItem Value="TimeDisplayTest.ascx">Кнопка 'время-дата'</asp:ListItem>
<asp:ListItem Value="LinkTableTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label></asp:Panel>
<br />
<asp:Panel ID="Panel2" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
EnableViewState="False" HorizontalAlign="Center">
<asp:DropDownList ID="DropDownList2" runat="server" AutoPostBack="True">
<asp:ListItem Value="None">(None)</asp:ListItem>
<asp:ListItem Value="HeaderTest.ascx">Верхний колонтитул</asp:ListItem>
<asp:ListItem Value="TimeDisplayTest.ascx">Кнопка 'время-дата'</asp:ListItem>
<asp:ListItem Value="LinkTableTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Label ID="Label2" runat="server" Text="Label"></asp:Label></asp:Panel>
<br />
<asp:Panel ID="Panel3" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
EnableViewState="False" HorizontalAlign="Center">
<asp:DropDownList ID="DropDownList3" runat="server" AutoPostBack="True">
<asp:ListItem Value="None">(None)</asp:ListItem>
<asp:ListItem Value="HeaderTest.ascx">Верхний колонтитул</asp:ListItem>
<asp:ListItem Value="TimeDisplayTest.ascx">Кнопка 'время-дата'</asp:ListItem>
<asp:ListItem Value="LinkTableTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder3" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Label ID="Label3" runat="server" Text="Label"></asp:Label></asp:Panel>
</div>
</form>
</body>
</html>
Выполните
сформированную страницу DynamicUserControls.aspx,
чтобы убедиться в работоспособности настроек режима проектированияМы выполнили интерфейсную заготовку портальных
каркасов на исполнимой странице. Теперь пришла пора наполнить
их функциональностью, которая бы обеспечила контейнерную загрузку
выбранных пользовательских элементов управления. Эту функциональность
мы обеспечим, кодируя застраничный файл DynamicUserControls.aspx.cs.
Ниже мы убедимся, что программно загруженные в портальные каркасы пользовательские элементы управления обрабатывают свои события точно также, как будто бы каждый из них находится на отдельной исполнимой странице.
Откройте
на редактирование файл DynamicUserControls.aspx.cs и
добавьте в класс DynamicUserControls следующий
кодusing System;
using System.Data;
using System.Configuration;
using System.Collections;
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 DynamicUserControls : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Загружаем портальные каркасы
MyLoadControls(Panel1);
MyLoadControls(Panel2);
MyLoadControls(Panel3);
}
// Вспомогательная функция
private void MyLoadControls(Control containerPanel)
{
// Объявляем вспомогательные ссылки на интерфейсные
// элементы текущего контейнера
DropDownList list = null;
PlaceHolder ph = null;
Label lbl = null;
// Перебираем все дочерние элементы текущего
// контейнера и ищем ссылки на объекты дочерних
// интерфейсных элементов по их типам
foreach (Control ctrl in containerPanel.Controls)
{
if (ctrl is DropDownList)
list = (DropDownList)ctrl;
else if (ctrl is PlaceHolder)
ph = (PlaceHolder)ctrl;
else if (ctrl is Label)
lbl = (Label)ctrl;
}
// Берем информацию из выделенного
// элемента списка текущего контейнера
string lstValue = list.SelectedItem.Value;
string lstText = list.SelectedItem.Text;
lbl.Text = "";
// Заполняем текущий контейнер.
// Проверяем наличие нужного расширения
if (lstValue.EndsWith(".ascx"))
{
ph.Controls.Add(Page.LoadControl(lstValue));
lbl.Text = "Загрузили: " + lstValue + " - " + lstText;
}
}
}
Пользовательский элемент управления иногда проще сделать из
обычной страницы .aspx, выполнив следующие
шаги:
aspx,
отладить ее и проверить в действииaspx в ascx@Page вместе с ее атрибутами
следует удалить и заменить @Control с
требуемыми атрибутами<html>, <body>, <form>, <head>Page на UserControl совмещенного кода
и файл имеет исполнимый код в блоке скриптов, то нужно в
Control обязательно
добавить атрибут ClassName =" имя_файла_или_любое_имя ".
Он извещает ASP.NET, что код, который нужно
компилировать, находится в том же файле в дескрипторах <script>.
Без этой информации файл компилироваться не будетИспользуя перечисленные шаги, создадим пользовательские элементы
управления, которые реализуют пользовательский интерфейс и
функциональность, использованную нами при выполнении предыдущих
упражнений в тестовых страницах. Из этих тестовых страниц мы
их и переделаем. Получится так, что пользовательский элемент
управления будет включен в тестовую страницу, а сама тестовая
страница будет превращена в пользовательский элемент и будет
динамически включаться по выбору из списка на исполнимую страницу DynamicUserControls.aspx в
зарезервированные -места.
В панели Solution Explore выделите при нажатой клавише Ctrl следующие файлыHeaderTest.aspxTimeDisplayTest.aspxLinkTableTest.aspxMyControlTest.aspx
Выполните
команду Copy затем Paste (на
верхнем узле проекта) контекстного меню
Присвойте
копиям те же самые имена, только с расширением .ascxHeaderTest.ascxTimeDisplayTest.ascxLinkTableTest.ascxMyControlTest.ascx
Откройте
новые файлы в дескрипторном режиме и замените @Page на @Control, все
остальные атрибуты бывшей @Page оставьте
прежними. Теперь это будут не страницы, а пользовательские
элементы управления. @Register с
ее атрибутами изменять не нужно
Удалить
из кода все дескрипторы <html>, <body>, <form>, <head> и
закрывающие их дескрипторыВ результате новые пользовательские элементы должны иметь следующий код интерфейсной части
| HeaderTest.ascx |
|---|
<%@ Control AutoEventWireup="true" CodeFile="HeaderTest.ascx.cs"
Inherits="HeaderTest" Language="C#" %>
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
<myElem:Header ID="Header1" runat="server" />
|
| TimeDisplayTest.ascx |
<%@ Control Language="C#" %>
<%@ Register Src="TimeDisplay.ascx" TagName="TimeDisplay" TagPrefix="uc1" %>
<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" />
|
| LinkTableTest.ascx |
<%@ Control AutoEventWireup="true" CodeFile="LinkTableTest.ascx.cs"
Inherits="LinkTableTest" Language="C#" %>
<%@ Register Src="LinkTable.ascx" TagName="LinkTable" TagPrefix="uc1" %>
<uc1:LinkTable ID="LinkTable1" runat="server"
OnLinkClicked="LinkTable1_LinkClicked" />
<br />
<asp:Label ID="lblInfo" runat="server"></asp:Label>
|
| MyControlTest.ascx |
<%@ Control AutoEventWireup="true" CodeFile="MyControlTest.ascx.cs"
Inherits="MyControlTest" Language="C#" %>
<%@ Register Src="MyControl.ascx" TagName="MyControl" TagPrefix="uc1" %>
<uc1:MyControl ID="MyControl1" runat="server" />
<br />
<br />
<asp:RadioButtonList ID="RadioButtonList1" runat="server"
OnSelectedIndexChanged="RadioButtonList1_SelectedIndexChanged"
RepeatDirection="Horizontal">
<asp:ListItem Value="Red">Красный</asp:ListItem>
<asp:ListItem Value="Green">Зеленый</asp:ListItem>
<asp:ListItem Value="Blue">Синий</asp:ListItem>
</asp:RadioButtonList>
<br />
<input id="Submit1" type="submit" value="submit" />
|
Для
новых файлов *.ascx откройте файлы скрытого
кода *.ascx.cs и замените в объявлении
класса имя System.Web.UI.Page " на
" System.Web.UI. UserControl "Остальной
код классов останется прежним. Мы закончили выполнение
упражнения. Код исполнимой страницы DynamicUserControls.aspx при очередной загрузке будет программно создавать свои пользовательские
элементы управления для каждого контейнера и
размещать их в элементах .
Выполните
страницу DynamicUserControls.aspx и испытайте
ее работуРезультат будет примерно таким


Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.