Пользовательские элементы управления (user control) разрабатывает сам программист в тех случаях, когда стандартные элементы управления его не удовлетворяют или он разработал удачный вариант кода. Такой элемент управления можно многократно использовать на многих страницах и последующие его модернизации немедленно будут отображаться на всех страницах, где он используется. Часто пользовательские элементы управления применяются для стандартизации (единообразия) интерфейса страниц, например, оформления верхнего и
Пользовательский элемент управления представляет собой небольшую часть страницы, которая может содержать статический
Файл пользовательского элемента управления может содержать то же самое, что и файл обычной исполнимой страницы, включая файл поддержки .cs, статический
<html>, <head >, <body>, <form>Среда проектирования позволяет видеть внедренный в страницу пользовательский элемент управления на поверхности конструктора Design страницы.
Рассмотрим эту задачу на примере. Заготовку пользовательского элемента управления легко создает мастер среды проектирования. Создадим пользовательский элемент управления, который будет представлять собой простой
Выполните команду Website/Add New Item, выберите шаблон Web User Control и задайте имя Header.ascx
Посмотрите, что создал мастер. Файл .ascx содержит только одну строку
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Header.ascx.cs" Inherits="Header" %>
Пользовательский элемент управления редактируется в оболочке точно также, как и обычная страница. Файл поддержки .ascx.cs содержит тот же код, что и для обычной страницы. В данном примере он нам не нужен, поэтому ничего в нем делать не будем (пусть болтается пустой).
Поместите в файл Header.ascx следующую HTML-разметку<table width="100%" border="0" bgcolor="blue">
<tr>
<td>
<font face="Vernada, Arial" size="6" color="yellow">
<b>Тестовая страница User Control</b>
</font> </td>
</tr>
<tr>
<td align="right">
<font size="3" color="white">
<b>Время создания: март 2007г. copy; Все права защищены</b>
</font> </td>
</tr>
</table>
Эта разметка даст такое визуальное представление

Продолжим рассмотрение нашего примера. Поскольку код пользовательского элемента управления предполагает его использование в страницах, то прежде всего создадим тестовую страницу.
Создайте новую страницу с именем HeaderTest.aspx для внедрения в нее пользовательского элемента управленияЧтобы использовать элемент управления на странице, нужно интегрировать его в форму. Для этого нужно выполнить следующие шаги:
<form> ссылку-тег на этот элемент.Директива @Register для нашего примера имеет следующий вид
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
Мы знаем, что для различения стандартных элементов управления в начале их дескрипторного представления используется конструкция <, например
<asp:TextBox ID="TextBox1" runat="server" />
Здесь играет роль TagPrefix (или условного пространства имен), а TextBox - тип элемента управления TagName. Директива регистрации также для лучшего различения пользовательских элементов управления поддерживает одинаковый синтаксис. Значения myElem и мы задали произвольно, но далее эти значения на странице мы должны строго соблюдать, а значение атрибута Src ( Source - источник) означает подключаемый файл с пользовательским элементом управления.
В зарегистрированных обозначениях пользовательского элемента управления синтаксис его подключения к странице HeaderTest.aspx будет таким (ну, как обычно!):
<myElem:Header ID="Header1" runat="server" ></myElem:Header>
или таким
<myElem:Header ID="Header1" runat="server" />
В результате пользовательская страница HeaderTest.aspx должна иметь такую HTML-разметку
<%@ Page AutoEventWireup="true" CodeFile="HeaderTest.aspx.cs" Inherits="HeaderTest"
Language="C#" %>
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Тест элемента user control</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<myElem:Header ID="Header1" runat="server" />
</div>
</form>
</body>
</html>
Вот таким образом к странице подключается файл, в котором содержится внешний частичный код. Этот код реально может быть любой сложности, включая все мыслимые элементы управления. Обратите внимание, что код файла Header.ascx не содержит ссылок на другие страницы и готов использоваться на любой странице как дополнение. С другой стороны, на файл пользовательского элемента, в свою очередь, может быть помещен другой пользовательский элемент, разработанный ранее. В таком случае этот подключаемый элемент нужно зарегистрировать на родителе точно так же, как это делается при подключении к конечной странице.
Запустите тестовую страницу на выполнение, должен получиться такой результат
В предыдущем примере мы не использовали код файла поддержки, хотя и создали его. Но чаще всего это нужно делать, чтобы добавить функциональность, которая может понадобиться клиенту. Как это делать, рассмотрим на простых примерах.
Для начала воспользуемся стандартным элементом управления LinkButton, который будет снимать с
Вызовите мастер для создания пользовательского элемента управления, выполнив команду Website/Add New Item. Установите шаблон в значение Web User Control, сбросьте флажок Place code in separate file и задайте имя файла TimeDisplay.ascx
Поместите в редактор Design стандартный элемент управления LinkButton из вкладки Standard
Через панель Properties измените ID элемента на lnkTime
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
Перетащите на нее из панели Solution Explorer файл TimeDisplay.ascx с пользовательским элементом управления
Выполните страницу, которая на клиенте будет такой
При каждом щелчке пользователя на ссылке-кнопке она будет снимать (и отображать) с
Свойство, это специальный член класса C#, который управляет доступом к члену-данному этого класса. Само данное называется полем и имеет определенный тип, устанавливающий резервируемую под хранение поля память. Свойство состоит из
get и set, содержащих контролирующий поле кодОсновное достоинство свойства состоит в том, что его можно использовать в выражениях и инструкциях присваивания как обычную переменную-член класса, хотя на самом деле здесь автоматически будут вызываться get - и set -аксессоры. Синтакис свойства таков:
модификатор_доступа тип имя_свойства
{
get
{
// код аксессора чтения поля
............................
return поле;
}
set
{
// код аксессора записи поля
............................
поле = value;
}
}
Пусть, например, переменной xField x, которому в программе можно присваивать только неотрицательные числа. Тогда простейший код свойства можно записать так
class MyClass
{
public MyClass()
{
xField = 0;
}
private int xField; // Это поле будет управляться свойством x
// Это свойство поддерживает доступ к закрытому полю xField
// через имя доступа x, равное имени свойства
// Для клиента этого класса x видна как переменная
public int x
{
get
{
return xField;
}
set
{
// Переменная value - зарезервированное имя переменной
// обобщенного типа, принимающей значение от клиента
// Это имя менять нельзя
if(value >= 0)
xField = value;
}
}
}
Теперь клиент класса будет видеть только переменную x, но при присваивании ей значения эта операция будет контролироваться кодом, следящим за тем, чтобы присваемые значения были неотрицательными.
Вернемся к нашей теме разработки пользовательского элемента управления. Расширим возможности предыдущего примера. Добавим в код общедоступное свойство Format, которому в клиенте (использующая элемент страница) будем передавать либо пустую строку, либо строку форматирования. В зависимости от этого пользовательский элемент управления будет способен отображать надпись на кнопке LinkButton в разных форматах.
Измените код файла TimeDisplay.ascx следующим образом(рис ) Улучшенный код файла TimeDisplay.ascx<%@ Control Language="C#" ClassName="xx" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
RefreshTime();
}
private string format; // Контролируемое свойством поле
public string Format // Определение свойства Format
{
get { return format; }
set { format = value; }
}
protected void lnkTime_Click(object sender, EventArgs e)
{
RefreshTime();
}
public void RefreshTime()
{
if (format == "")
lnkTime.Text = DateTime.Now.ToLongTimeString();
else // Значение format задаем в клиенте через свойство Format
lnkTime.Text = DateTime.Now.ToString(format);
}
</script>
<asp:LinkButton ID="lnkTime" runat="server" OnClick="lnkTime_Click" />
Измените код тестовой страницы TimeDisplayTest.aspx следующим образом(рис ) Код тестовой страницы TimeDisplayTest.aspx<%@ Page Language="C#" %>
<%@ Register Src="TimeDisplay.ascx" TagName="TimeDisplay" TagPrefix="uc1" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Страница TimeDisplayTest</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
Сделайте эту страницу стартовой
Добавьте к проекту новую папку с зарезервированным именем
Через контекстное меню на созданной папке выполните команду
Через окно мастера добавьте к приложению новый класс C# с именем Этот класс в своих полях будет хранить информацию, необходимую пользовательскому элементу управления, а через свойства осуществлять доступ к ней.
Заполните вспомогательный класс в файле LinkTableItem.cs следующим кодом(рис ) Код файла App_Code/LinkTableItem.csusing 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; }
}
}
Теперь нужно создать пользовательский элемент, который будет управлять этим вспомогательным классом.
Создайте заготовку пользовательского элемента управления
Поместите в таблицу пользовательского элемента следующие стандартные компоненты:Table из вкладки HTML, который будет форматировать размещение стандартных элементов управленияLabel из вкладки Standard в верхнюю ячейку таблицы, который будет определять заголовок набора ссылокImage из вкладки HTML, определяющий рисунок маркера ссылокDataList из вкладки Data в нижнюю ячейку таблицыHyperLink из вкладки Standard
Настройте дескрипторный код пользовательского элемента управления так<%@ Control Language="C#" AutoEventWireup="true" CodeFile="LinkTable.ascx.cs"
Inherits="LinkTable" %>
<table border="1" cellpadding="2" cellspacing="0" width="100%">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server"
ForeColor="#C00000" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small">
<!--Здесь будет заголовок-->
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img width="25" height="13" src="Yes.gif" alt="маркер">
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
Text='<%# DataBinder.Eval(Container.DataItem, "Text") %>' />
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
задает альтернативную надпись в поле рисунка, если последний не будет найден.
Теперь пришла пора расширить функциональность пользовательского элемента управления 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, то событие не произошло, поскольку нет соответствующего объекта. Один объект генерирует событие (создает экземпляр) и посылает уведомление через канал сообщений операционной системы. Другие, подписанные на это событие объекты приложения, получают это сообщение вместе с дополнительной информацией и запускают соответствующие обработчики, предварительно передав им дополнительную информацию в качестве аргументов.
Для объявления адресной переменной события используются делегаты.
С помощью конструктора
Вот так лениво, общими словами, без соответствующих примеров кода мы обозрели механизм использования событий и делегатов в чистом C#. Будем считать, что мы будто бы вспомнили те азы языка C#, которые нам должны были давать вместо
Мы эту задачу поставим как развитие предыдущего примера, поэтому для дальнейшей работы нужно создать копию файлов этого примера.
В панели Solution Explorer, удерживая клавишу Ctrl, выделите узлы LinkTable.ascx и LinkTableTest.aspx
Через контекстное меню панели выполните команду Copy, а затем через контекстное меню на узле проекта (вверху) выполните команду Paste
Переименуйте созданные копии в имена оригиналов, но с добавлением Ext (
Сделайте страницу LinkTableExtTest.aspx стартовой, выполнив на ее узле в представлении панели Solution Explorer команду Set As Start Page контекстного меню
Подправьте в файле LinkTableExtTest.aspx декларацию @Register, чтобы новая тестовая страница применяла пользовательский элемент управления из другого файла<%@ Register Src="LinkTableExt.ascx" TagName="LinkTable" TagPrefix="uc1" %>
Запустите новую тестовую страницу на выполнение, чтобы убедиться в ее работоспособности с прежней функциональностьюВсе, теперь мы готовы модернизировать новые файлы предыдущего примера. Посмотрим, что мы хотим сделать.
В предыдущем примере мы с помощью вспомогательного класса LinkTableItem могли добавлять в классе пользовательского элемента управления LinkTableTest новые к элементу . По щелчку клиента на одной из гиперссылок он безусловно направлялся по указанному адресу. Теперь же мы хотим перехватывать и распознавать щелчок на любой
Ранее в дескрипторном представлении пользовательского элемента управления мы применяли стандартный элемент . Если посмотреть на класс этого элемента System.Web.UI. через панель Object Browser, то можно увидеть, что он не имеет никаких событий

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

Эти события мы и будем перехватывать в нашем элементе управления.
Измените тип элемента в шаблоне <ItemTemplate> дескрипторного представления файла LinkTableExt.ascx и новое имя атрибута CommandArgument, после чего файл должен быть таким<%@ Control Language="C#" AutoEventWireup="true" CodeFile="LinkTableExt.ascx.cs"
Inherits="LinkTable" %>
<table border="1" cellpadding="2" cellspacing="0" width="100%">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server"
ForeColor="#C00000" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small">
<!--Здесь будет заголовок-->
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img width="25" height="13" src="Yes.gif" alt="маркер">
<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. Объявим также
Откройте файл LinkTableExt.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();
}
}
}
// Объявляем делегат события 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 поддержки пользовательского элемента управления.
Откройте на редактирование файл LinkTableExt.ascx в режиме Design
Выделите пользовательский элемент управления и в панели Properties создайте обработчик для события

Добавьте в класс LinkTable и созданный обработчик стандартного события следующий код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();
}
}
// Объявляем в классе наше событие 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
// в глобальной области видимости,
// который определит сигнатуру события и обработчика
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 будет возникать всякий раз, когда пользователь щелкнет на
Учитывая, что в режиме проектирования оболочка поддерживает автоматическое создание обработчиков через панель Properties только для событий библиотечных классов, создадим заготовку обработчика вручную. При этом нужно соблюсти
Откройте на редактирование файл LinkTableExtTest.aspx.cs и в конце обработчика события Page_Load() класса LinkTableTest начните набирать LinkTable1, под которым на тестовой странице у нас числится экземпляр зарегистрированного на ней пользовательского элемента управления. Вы сразу увидите реакцию подсказчика кода IntelliSense
Нажав два раза клавишу Tab мы получим и регистрацию события в классе-приемнике через глобального
LinkTable1.LinkClicked += new LinkClickedEventHandler(LinkTable1_LinkClicked);
Если выбрать второй способ, тогда нужно в дескрипторном представлении пользовательского элемента добавить атрибут OnLinkClicked="LinkTable1_LinkClicked", чтобы привязать к событию созданный обработчик (обратите внимание, что имя атрибута формируется из имени события и On ). Но и в этом случае Большой Билл нам тоже чуть-чуть помогает

Давайте выберем второй способ...
Уничтожте регистрацию события в классе LinkTableTest, скопируйте имя сгенерированного обработчика и добавьте его в атрибут OnLinkClicked="LinkTable1_LinkClicked" <uc1:LinkTable ID="LinkTable1" runat="server" /> файла тестовой страницы LinkTableExtTest.aspx
В режиме Design тестовой страницы разместите текстовую метку asp :Label из вкладки Standard, задайте ей имя lblInfo и очистите поле ее свойства Text (либо удалите одноименный атрибут в
Вернитесь в файл LinkTableExtTest.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;
}
public 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 + "!!!";
}
}
}
Запустите тестовую страницу LinkTableExtTest.aspx и полюбуйтесь на свою работу
Web-страница, которая содержит
Но учитывая, что сам пользовательский элемент имеет доступ к своим компонентам, а страница имеет доступ к пользовательскому элементу, это правило можно обойти. Для этого существует два способа:
В пользовательский элемент вводят промежуточные свойства или private упаковывают в функции доступа public, которые сами видят эти переменные, а их, в свою очередь, видят клиенты этого класса.
Пусть, например, пользовательский элемент управления MyControl1 как объект порождается классом MyControl и в качестве одного из компонентов содержит в себе объект Label1 библиотечного класса System.Web.UI.. Класс наследует от 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; }
}
}
Здесь мы использовали имена посреднических свойств родителя MyControl1 точно такие, как у прямых свойств компонента Label1. Но это не обязательно. Можно использовать любые имена. Просто, когда Иванов, Петров, Сидоров означают одно и то же лицо, но в разных инстанция числятся по разному, это " хужее ".
Создайте пользовательскую тестовую страницу с раздельным кодом под именем MyControlTest.aspx и переведите ее в режим редактирования Design
Из панели Solution Explorer из дерева файлов приложения перенесите на тестовую страницу узел MyControl.ascx. Убедитесь, что экземпляр пользовательского элемента управления зарегистрировался на тестовой странице под именем MyControl1
Попробуйте выделить элемент управления и убедитесь, что он не выделяется и добавленные нами свойства не видны в панели Properties. Это значит, что декларативно (в режиме проектирования) из страницы настраивать его нелься, но можно программно управлять (в режиме выполнения) через введенные нами общедоступные свойства, в чем мы и хотим убедиться.
Поместите на страницу под пользовательским элементом управления компонент RadioButtonList из вкладки Standard и убедитесь, что он имеет ID="RadioButtonList1"
Через коллекцию Items элемента RadioButtonList1 задайте три радиокнопки с такими свойствамиText="Красный"; Value="Red"Text="Зеленый"; Value="Green "Text="Синий"; Value="Blue "
Установите свойство 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 сгенерирует нужный
Заполните обработчик RadioButtonList1_SelectedIndexChanged() страницы в файле MyControlTest.aspx.cs следующим кодом(рис ) Код обработчика в файле MyControlTest.aspx.csusing 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, хотя он входит в состав пользовательского элемента управления MyControl1. Взаимодействие страницы с Label1 происходит через добавленные нами в пользовательский элемент управления дополнительные глобальные свойства.Есть еще один способ обеспечить доступ к компонентам,
Поясним сказанное на предыдущем примере.
Скопируйте через панель Solution Explorer, как это мы делали ранее, файл тестовой страницы MyControlTest.aspx и файл пользовательского элемента управления MyControl.ascx
Присвойте копиям новые имена MyControlExtTest.aspx и MyControlExt.ascx соответственно (файлы сопровождающего скрытого кода оболочка переименует автоматически)
Сделайте страницу MyControlExtTest.aspx стартовой, выполнив на ее узле в панели Solution Explorer команду Set As Start Page
Измените параметр Src <%@ Register Src="MyControlExt.ascx" TagName="MyControl" TagPrefix="uc1" %>
Откройте файл скрытого кода MyControlExt.ascx.cs и измените в нем класс MyControl, чтобы он выглядел так(рис ) Добавление в класс пользовательского элемента управления свойства-ссылки на его внутренний компонент Label1 в файле MyControlExt.ascx.csusing 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"
Откройте файл MyControlExtTest.aspx.cs скрытого кода тестовой страницы и отредактируйте его для доступа к прямым свойствам компонента Label1 с использованием созданного адреса InnerLabel1(рис ) Доступ к прямым свойствам Label1 через адрес InnerLabel1 на странице MyControlExtTest.aspxusing 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 MyControlExtTest : 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;
}
}
Выполните страницу и убедитесь, что получился тот же самый результат, что и в предыдущем примере при реализации первого способа
Какой способ выбрать - решать Вам.
На протяжении этой темы мы рассматривали вопрос создания пользовательского элемента управления в режиме проектирования и последующее управление им в программном режиме. Но может потребоваться на странице подгружать и настраивать пользовательский элемент управления динамически ("на лету"). Мы уже программно создавали из библиотечного элемента управления HtmlTable объект-таблицу на странице DynamicTable.aspx. Теперь посмотрим, как это делается для пользовательского элемента управления.
Требуется выполнить следующие шаги:
Page.Load экземпляр класса пользовательского элемента управления, заранее подготовленного в файлах *.ascx и *.ascx.cs. Создание и регистрация экземпляра пользовательского элемента в коде страницы осуществляется Page.LoadControl().PlaceHolder место размещения для точного ID пользовательского элемента управления, особенно, когда создается несколько экземпляров одного и того же элемента. Это может понадобиться для однозначной идентификации элемента в коде страницы при поиске ссылки на экземпляр, выполняемом с помощью статического метода Page.FindControl(), который как раз использует значение идентификатора ID.Есть некоторая специфика динамического создания пользовательского элемента управления. Нельзя создать пользовательский элемент напрямую, как это делается с библиотечным элементом управления через
Скопируйте через панель Solution Explorer, как это мы делали ранее, файл тестовой страницы MyControlExtTest.aspx и файл пользовательского элемента управления MyControlExt.ascx
Присвойте копиям новые имена MyControlDynamicTest.aspx и MyControlDynamic.ascx соответственно (файлы сопровождающего скрытого кода оболочка переименует автоматически)
Сделайте страницу MyControlDynamicTest.aspx стартовой, выполнив на ее узле в панели Solution Explorer команду Set As Start Page
Закройте все предыдущие редактируемые документы командой меню Window/Close All Documents
Откройте на редактирование страницу MyControlDynamicTest.aspx в режиме Design, удалите наш пользовательский элемент управления Label1 и поместите на его место из вкладки Standard стандартный элемент управления PlaceHolder
Перейдите в файле MyControlDynamicTest.aspx в режим Source редактора страницы и удалите полностью старый код <%@ Register Src="MyControlExt.ascx" TagName="MyControl" TagPrefix="uc1" %>
На данном этапе страница в дескрипторном представлении будет такой
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="MyControlDynamicTest.aspx.cs"
Inherits="MyControlTest" %>
<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. Далее мы программно должны создать этот элемент, добавить ссылку на него к странице, а потом и управлять свойствами его компонентов.
Откройте на редактирование файл скрытого кода
Измените код обработчика 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 MyControlTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Создаем экземпляр класса поддержки
// пользовательского элемента управления
MyControl MyControl1 = (MyControl)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.
Чаще пользовательский элемент управления проще сделать из обычной страницы .aspx, чем мы и воспользуемся ниже. Это делается так:
@Page вместе с ее атрибутами следует удалить и заменить @Control с требуемыми атрибутами.<html>, <body>, <form>, <head >.Page на UserControl .Control обязательно добавить атрибут ClassName="имя_файла_или_любое_имя". Он извещает ASP.NET, что код, который нужно компилировать, находится в том же файле в дескрипторах <script >. Без этой информации файл компилироваться не будет.Итак, мы разработали несколько пользовательских элементов управления:
Для каждого из этих элементов управления разрабатывалась своя тестовая страница, на которую элемент управления помещался декларативно. Только в последнем случае мы сам пользовательский элемент не изменяли, но на тестовой странице создавали его динамически (программно). Теперь давайте на примере рассмотрим вопрос, когда на страницу нужно поместить программно сразу несколько разных пользовательских элементов управления.
Создайте новую страницу DynamicUserControls.aspx с раздельным кодом и сделайте ее стартовой
В раскрывающемся списке панели Properties выберите элемент DOCUMENT и задайте его свойству Title значение Портальные каркасы
В режиме Design поместите с вкладки Standard элемент Panel и присвойте ему имя Panel1 (оно генерируется автоматически). Этот элемент будет служить контейнером для других элементов управления, в том числе и для пользовательского
Поместите внутрь контейнера Panel1 друг за другом по вертикали стандартные элементыDropDownList с автоматически сгенерированным именем DropDownList1 - для выбора загружаемого в контейнер пользовательского элемента управленияPlaceHolder с автоматически сгенерированным именем PlaceHolder1 - для Label с автоматически сгенерированным именем Label1 - для отображения имени файла, из которого в контейнер загружен пользовательский элемент управленияПо большому счету нам в данном примере безразлично, какие имена будут иметь экземпляры дочерних элементов. Однозначно различать их в коде мы можем по найденным ссылкам. Ссылки, в свою очередь, будем искать в именованном контейнере по типу дочернего элемента, поскольку помещенные нами элементы имеют разный тип. Но сама оболочка Visual Studio 2005 требует, чтобы на странице не было декларативно объявляемых ID.
Проследите в дескрипторном представлении страницы, чтобы ни один из элементов, включая контейнер, не имел атрибутов Width и Height , ограничивающих свободную Заметим, что контейнер Panel1, как родитель, по умолчанию будет определять основные свойства своих дочерних элементов, такие как
Ранее мы перечислили пользовательские элементы управления, которые создали в данной работе. Выберем несколько из них для динамического размещения. Имена этих элементов нужно занести в список DropDownList1. Пусть это будут элементы:
Выделите объект DropDownList1 в контейнере Place1 и заполните декларативно его свойство Items так| Text | Value | |
|---|---|---|
|
(None) | None |
|
HeaderTest.ascx |
|
|
Кнопка 'время-дата' | TimeDisplayTest.ascx |
|
Список гиперссылок | LinkTableTest.ascx |
|
Контролируемый список гиперссылок | LinkTableExtTest.ascx |
|
С настройкой внутренних компонентов | MyControlTest.ascx |
В Value мы указали имена файлов, которые в будущем должны будем создать
Установите для элемента DropDownList1 его свойство AutoPostBack в значение True, чтобы обеспечить постинг страницы при выборе пользователем нужной опцииБудем считать, что один из трех стандартных элементов управления контейнера, а именно список, мы заполнили декларативно. Два других элемента контейнера будем заполнять программно.
Таким образом, один контейнер мы почти настроили. Но мы хотим разместить на странице три таких контейнера, чтобы иметь возможность в каждый из них программно загружать выбранные через список DropDownList1 пользовательские элементы управления. При этом мы хотим убедиться, что они работают независимо друг от друга и каждый делает то, что должен путем реагирования на свои собственные события.
В режиме Design тестовой страницы разместите по вертикали друг за другом три копии контейнера Place1 вместе с его дочерними элементами. Проследите, чтобы контейнеры имели имена Panel1, Panel2, Panel3
Через раскрывающийся список панели Properties выделяйте последовательно каждый контейнер Panel1, Panel2, Panel3 и настройте их свойства такBackColor=Web/GainsboroBorderWidth =1pxHorizontalAlign=CenterBorderStyle =Ridge EnableViewState="False"Мы закончили
<%@ Page AutoEventWireup="true" CodeFile="DynamicUserControls.aspx.cs" Inherits="DynamicUserControls"
Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Портальные каркасы</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel ID="Panel1" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
HorizontalAlign="Center" EnableViewState="False">
<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="LinkTableExtTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
<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="LinkTableExtTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>
<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="LinkTableExtTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder3" runat="server"></asp:PlaceHolder>
<br />
<asp:Label ID="Label3" runat="server" Text="Label"></asp:Label></asp:Panel>
<br />
</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;
}
}
}
Создадим пользовательские элементы управления, которые реализуют пользовательский интерфейс и функциональность, использованную нами при выполнении примеров в тестовых страницах. Из этих тестовых страниц мы их и переделаем.
В панели Solution Explore выделите при нажатой клавише Ctrl следующие файлы
Выполните команду Copy затем Paste (на верхнем узле проекта) контекстного меню
Присвойте копиям те же самые имена, только с расширением .ascx
Откройте новые файлы в дескрипторном режиме и замените @Page на @Control, все остальные атрибуты @Page оставьте прежними. Теперь это будут не страницы, а пользовательские элементы управления. @Register с ее атрибутами оставьте в покое
Удалить из кода все <html>, <body>, <form>, <head > и закрывающие их
Для новых файлов *.ascx откройте файлы скрытого кода *.ascx.cs и замените в объявлении класса имя наследующего класса с " : System.Web.UI.Page " на " : System.Web.UI.UserControl ". Остальной код классов останется прежним.Мы закончили выполнение примера. Код тестовой страницы при очередной загрузке будет программно создавать свои пользовательские элементы управления для каждого контейнера и размещать их в элементах .
Выполните страницу DynamicUserControls.aspx и испытайте ее. Результат будет примерно таким
Пользовательские элементы управления (user control) разрабатывает сам программист в тех случаях, когда стандартные элементы управления его не удовлетворяют или он разработал удачный вариант кода. Такой элемент управления можно многократно использовать на многих страницах и последующие его модернизации немедленно будут отображаться на всех страницах, где он используется. Часто пользовательские элементы управления применяются для стандартизации (единообразия) интерфейса страниц, например, оформления верхнего и
Пользовательский элемент управления представляет собой небольшую часть страницы, которая может содержать статический
Файл пользовательского элемента управления может содержать то же самое, что и файл обычной исполнимой страницы, включая файл поддержки .cs, статический
<html>, <head >, <body>, <form>Среда проектирования позволяет видеть внедренный в страницу пользовательский элемент управления на поверхности конструктора Design страницы.
Рассмотрим эту задачу на примере. Заготовку пользовательского элемента управления легко создает мастер среды проектирования. Создадим пользовательский элемент управления, который будет представлять собой простой
Выполните команду Website/Add New Item, выберите шаблон Web User Control и задайте имя Header.ascx
Посмотрите, что создал мастер. Файл .ascx содержит только одну строку
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Header.ascx.cs" Inherits="Header" %>
Пользовательский элемент управления редактируется в оболочке точно также, как и обычная страница. Файл поддержки .ascx.cs содержит тот же код, что и для обычной страницы. В данном примере он нам не нужен, поэтому ничего в нем делать не будем (пусть болтается пустой).
Поместите в файл Header.ascx следующую HTML-разметку<table width="100%" border="0" bgcolor="blue">
<tr>
<td>
<font face="Vernada, Arial" size="6" color="yellow">
<b>Тестовая страница User Control</b>
</font> </td>
</tr>
<tr>
<td align="right">
<font size="3" color="white">
<b>Время создания: март 2007г. copy; Все права защищены</b>
</font> </td>
</tr>
</table>
Эта разметка даст такое визуальное представление

Продолжим рассмотрение нашего примера. Поскольку код пользовательского элемента управления предполагает его использование в страницах, то прежде всего создадим тестовую страницу.
Создайте новую страницу с именем HeaderTest.aspx для внедрения в нее пользовательского элемента управленияЧтобы использовать элемент управления на странице, нужно интегрировать его в форму. Для этого нужно выполнить следующие шаги:
<form> ссылку-тег на этот элемент.Директива @Register для нашего примера имеет следующий вид
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
Мы знаем, что для различения стандартных элементов управления в начале их дескрипторного представления используется конструкция <, например
<asp:TextBox ID="TextBox1" runat="server" />
Здесь играет роль TagPrefix (или условного пространства имен), а TextBox - тип элемента управления TagName. Директива регистрации также для лучшего различения пользовательских элементов управления поддерживает одинаковый синтаксис. Значения myElem и мы задали произвольно, но далее эти значения на странице мы должны строго соблюдать, а значение атрибута Src ( Source - источник) означает подключаемый файл с пользовательским элементом управления.
В зарегистрированных обозначениях пользовательского элемента управления синтаксис его подключения к странице HeaderTest.aspx будет таким (ну, как обычно!):
<myElem:Header ID="Header1" runat="server" ></myElem:Header>
или таким
<myElem:Header ID="Header1" runat="server" />
В результате пользовательская страница HeaderTest.aspx должна иметь такую HTML-разметку
<%@ Page AutoEventWireup="true" CodeFile="HeaderTest.aspx.cs" Inherits="HeaderTest"
Language="C#" %>
<%@ Register TagPrefix="myElem" TagName="Header" Src="Header.ascx" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Тест элемента user control</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<myElem:Header ID="Header1" runat="server" />
</div>
</form>
</body>
</html>
Вот таким образом к странице подключается файл, в котором содержится внешний частичный код. Этот код реально может быть любой сложности, включая все мыслимые элементы управления. Обратите внимание, что код файла Header.ascx не содержит ссылок на другие страницы и готов использоваться на любой странице как дополнение. С другой стороны, на файл пользовательского элемента, в свою очередь, может быть помещен другой пользовательский элемент, разработанный ранее. В таком случае этот подключаемый элемент нужно зарегистрировать на родителе точно так же, как это делается при подключении к конечной странице.
Запустите тестовую страницу на выполнение, должен получиться такой результат
В предыдущем примере мы не использовали код файла поддержки, хотя и создали его. Но чаще всего это нужно делать, чтобы добавить функциональность, которая может понадобиться клиенту. Как это делать, рассмотрим на простых примерах.
Для начала воспользуемся стандартным элементом управления LinkButton, который будет снимать с
Вызовите мастер для создания пользовательского элемента управления, выполнив команду Website/Add New Item. Установите шаблон в значение Web User Control, сбросьте флажок Place code in separate file и задайте имя файла TimeDisplay.ascx
Поместите в редактор Design стандартный элемент управления LinkButton из вкладки Standard
Через панель Properties измените ID элемента на lnkTime
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
Перетащите на нее из панели Solution Explorer файл TimeDisplay.ascx с пользовательским элементом управления
Выполните страницу, которая на клиенте будет такой
При каждом щелчке пользователя на ссылке-кнопке она будет снимать (и отображать) с
Свойство, это специальный член класса C#, который управляет доступом к члену-данному этого класса. Само данное называется полем и имеет определенный тип, устанавливающий резервируемую под хранение поля память. Свойство состоит из
get и set, содержащих контролирующий поле кодОсновное достоинство свойства состоит в том, что его можно использовать в выражениях и инструкциях присваивания как обычную переменную-член класса, хотя на самом деле здесь автоматически будут вызываться get - и set -аксессоры. Синтакис свойства таков:
модификатор_доступа тип имя_свойства
{
get
{
// код аксессора чтения поля
............................
return поле;
}
set
{
// код аксессора записи поля
............................
поле = value;
}
}
Пусть, например, переменной xField x, которому в программе можно присваивать только неотрицательные числа. Тогда простейший код свойства можно записать так
class MyClass
{
public MyClass()
{
xField = 0;
}
private int xField; // Это поле будет управляться свойством x
// Это свойство поддерживает доступ к закрытому полю xField
// через имя доступа x, равное имени свойства
// Для клиента этого класса x видна как переменная
public int x
{
get
{
return xField;
}
set
{
// Переменная value - зарезервированное имя переменной
// обобщенного типа, принимающей значение от клиента
// Это имя менять нельзя
if(value >= 0)
xField = value;
}
}
}
Теперь клиент класса будет видеть только переменную x, но при присваивании ей значения эта операция будет контролироваться кодом, следящим за тем, чтобы присваемые значения были неотрицательными.
Вернемся к нашей теме разработки пользовательского элемента управления. Расширим возможности предыдущего примера. Добавим в код общедоступное свойство Format, которому в клиенте (использующая элемент страница) будем передавать либо пустую строку, либо строку форматирования. В зависимости от этого пользовательский элемент управления будет способен отображать надпись на кнопке LinkButton в разных форматах.
Измените код файла TimeDisplay.ascx следующим образом(рис ) Улучшенный код файла TimeDisplay.ascx<%@ Control Language="C#" ClassName="xx" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
RefreshTime();
}
private string format; // Контролируемое свойством поле
public string Format // Определение свойства Format
{
get { return format; }
set { format = value; }
}
protected void lnkTime_Click(object sender, EventArgs e)
{
RefreshTime();
}
public void RefreshTime()
{
if (format == "")
lnkTime.Text = DateTime.Now.ToLongTimeString();
else // Значение format задаем в клиенте через свойство Format
lnkTime.Text = DateTime.Now.ToString(format);
}
</script>
<asp:LinkButton ID="lnkTime" runat="server" OnClick="lnkTime_Click" />
Измените код тестовой страницы TimeDisplayTest.aspx следующим образом(рис ) Код тестовой страницы TimeDisplayTest.aspx<%@ Page Language="C#" %>
<%@ Register Src="TimeDisplay.ascx" TagName="TimeDisplay" TagPrefix="uc1" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Страница TimeDisplayTest</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
Сделайте эту страницу стартовой
Добавьте к проекту новую папку с зарезервированным именем
Через контекстное меню на созданной папке выполните команду
Через окно мастера добавьте к приложению новый класс C# с именем Этот класс в своих полях будет хранить информацию, необходимую пользовательскому элементу управления, а через свойства осуществлять доступ к ней.
Заполните вспомогательный класс в файле LinkTableItem.cs следующим кодом(рис ) Код файла App_Code/LinkTableItem.csusing 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; }
}
}
Теперь нужно создать пользовательский элемент, который будет управлять этим вспомогательным классом.
Создайте заготовку пользовательского элемента управления
Поместите в таблицу пользовательского элемента следующие стандартные компоненты:Table из вкладки HTML, который будет форматировать размещение стандартных элементов управленияLabel из вкладки Standard в верхнюю ячейку таблицы, который будет определять заголовок набора ссылокImage из вкладки HTML, определяющий рисунок маркера ссылокDataList из вкладки Data в нижнюю ячейку таблицыHyperLink из вкладки Standard
Настройте дескрипторный код пользовательского элемента управления так<%@ Control Language="C#" AutoEventWireup="true" CodeFile="LinkTable.ascx.cs"
Inherits="LinkTable" %>
<table border="1" cellpadding="2" cellspacing="0" width="100%">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server"
ForeColor="#C00000" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small">
<!--Здесь будет заголовок-->
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img width="25" height="13" src="Yes.gif" alt="маркер">
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl='<%# DataBinder.Eval(Container.DataItem, "Url") %>'
Text='<%# DataBinder.Eval(Container.DataItem, "Text") %>' />
</ItemTemplate>
</asp:DataList>
</td>
</tr>
</table>
задает альтернативную надпись в поле рисунка, если последний не будет найден.
Теперь пришла пора расширить функциональность пользовательского элемента управления 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, то событие не произошло, поскольку нет соответствующего объекта. Один объект генерирует событие (создает экземпляр) и посылает уведомление через канал сообщений операционной системы. Другие, подписанные на это событие объекты приложения, получают это сообщение вместе с дополнительной информацией и запускают соответствующие обработчики, предварительно передав им дополнительную информацию в качестве аргументов.
Для объявления адресной переменной события используются делегаты.
С помощью конструктора
Вот так лениво, общими словами, без соответствующих примеров кода мы обозрели механизм использования событий и делегатов в чистом C#. Будем считать, что мы будто бы вспомнили те азы языка C#, которые нам должны были давать вместо
Мы эту задачу поставим как развитие предыдущего примера, поэтому для дальнейшей работы нужно создать копию файлов этого примера.
В панели Solution Explorer, удерживая клавишу Ctrl, выделите узлы LinkTable.ascx и LinkTableTest.aspx
Через контекстное меню панели выполните команду Copy, а затем через контекстное меню на узле проекта (вверху) выполните команду Paste
Переименуйте созданные копии в имена оригиналов, но с добавлением Ext (
Сделайте страницу LinkTableExtTest.aspx стартовой, выполнив на ее узле в представлении панели Solution Explorer команду Set As Start Page контекстного меню
Подправьте в файле LinkTableExtTest.aspx декларацию @Register, чтобы новая тестовая страница применяла пользовательский элемент управления из другого файла<%@ Register Src="LinkTableExt.ascx" TagName="LinkTable" TagPrefix="uc1" %>
Запустите новую тестовую страницу на выполнение, чтобы убедиться в ее работоспособности с прежней функциональностьюВсе, теперь мы готовы модернизировать новые файлы предыдущего примера. Посмотрим, что мы хотим сделать.
В предыдущем примере мы с помощью вспомогательного класса LinkTableItem могли добавлять в классе пользовательского элемента управления LinkTableTest новые к элементу . По щелчку клиента на одной из гиперссылок он безусловно направлялся по указанному адресу. Теперь же мы хотим перехватывать и распознавать щелчок на любой
Ранее в дескрипторном представлении пользовательского элемента управления мы применяли стандартный элемент . Если посмотреть на класс этого элемента System.Web.UI. через панель Object Browser, то можно увидеть, что он не имеет никаких событий

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

Эти события мы и будем перехватывать в нашем элементе управления.
Измените тип элемента в шаблоне <ItemTemplate> дескрипторного представления файла LinkTableExt.ascx и новое имя атрибута CommandArgument, после чего файл должен быть таким<%@ Control Language="C#" AutoEventWireup="true" CodeFile="LinkTableExt.ascx.cs"
Inherits="LinkTable" %>
<table border="1" cellpadding="2" cellspacing="0" width="100%">
<tr>
<td>
<asp:Label ID="lblTitle" runat="server"
ForeColor="#C00000" Font-Bold="true"
Font-Names="Vernada" Font-Size="Small">
<!--Здесь будет заголовок-->
</asp:Label>
</td>
</tr>
<tr>
<td>
<asp:DataList ID="listContent" runat="server">
<ItemTemplate>
<img width="25" height="13" src="Yes.gif" alt="маркер">
<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. Объявим также
Откройте файл LinkTableExt.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();
}
}
}
// Объявляем делегат события 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 поддержки пользовательского элемента управления.
Откройте на редактирование файл LinkTableExt.ascx в режиме Design
Выделите пользовательский элемент управления и в панели Properties создайте обработчик для события

Добавьте в класс LinkTable и созданный обработчик стандартного события следующий код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();
}
}
// Объявляем в классе наше событие 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
// в глобальной области видимости,
// который определит сигнатуру события и обработчика
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 будет возникать всякий раз, когда пользователь щелкнет на
Учитывая, что в режиме проектирования оболочка поддерживает автоматическое создание обработчиков через панель Properties только для событий библиотечных классов, создадим заготовку обработчика вручную. При этом нужно соблюсти
Откройте на редактирование файл LinkTableExtTest.aspx.cs и в конце обработчика события Page_Load() класса LinkTableTest начните набирать LinkTable1, под которым на тестовой странице у нас числится экземпляр зарегистрированного на ней пользовательского элемента управления. Вы сразу увидите реакцию подсказчика кода IntelliSense
Нажав два раза клавишу Tab мы получим и регистрацию события в классе-приемнике через глобального
LinkTable1.LinkClicked += new LinkClickedEventHandler(LinkTable1_LinkClicked);
Если выбрать второй способ, тогда нужно в дескрипторном представлении пользовательского элемента добавить атрибут OnLinkClicked="LinkTable1_LinkClicked", чтобы привязать к событию созданный обработчик (обратите внимание, что имя атрибута формируется из имени события и On ). Но и в этом случае Большой Билл нам тоже чуть-чуть помогает

Давайте выберем второй способ...
Уничтожте регистрацию события в классе LinkTableTest, скопируйте имя сгенерированного обработчика и добавьте его в атрибут OnLinkClicked="LinkTable1_LinkClicked" <uc1:LinkTable ID="LinkTable1" runat="server" /> файла тестовой страницы LinkTableExtTest.aspx
В режиме Design тестовой страницы разместите текстовую метку asp :Label из вкладки Standard, задайте ей имя lblInfo и очистите поле ее свойства Text (либо удалите одноименный атрибут в
Вернитесь в файл LinkTableExtTest.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;
}
public 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 + "!!!";
}
}
}
Запустите тестовую страницу LinkTableExtTest.aspx и полюбуйтесь на свою работу
Web-страница, которая содержит
Но учитывая, что сам пользовательский элемент имеет доступ к своим компонентам, а страница имеет доступ к пользовательскому элементу, это правило можно обойти. Для этого существует два способа:
В пользовательский элемент вводят промежуточные свойства или private упаковывают в функции доступа public, которые сами видят эти переменные, а их, в свою очередь, видят клиенты этого класса.
Пусть, например, пользовательский элемент управления MyControl1 как объект порождается классом MyControl и в качестве одного из компонентов содержит в себе объект Label1 библиотечного класса System.Web.UI.. Класс наследует от 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; }
}
}
Здесь мы использовали имена посреднических свойств родителя MyControl1 точно такие, как у прямых свойств компонента Label1. Но это не обязательно. Можно использовать любые имена. Просто, когда Иванов, Петров, Сидоров означают одно и то же лицо, но в разных инстанция числятся по разному, это " хужее ".
Создайте пользовательскую тестовую страницу с раздельным кодом под именем MyControlTest.aspx и переведите ее в режим редактирования Design
Из панели Solution Explorer из дерева файлов приложения перенесите на тестовую страницу узел MyControl.ascx. Убедитесь, что экземпляр пользовательского элемента управления зарегистрировался на тестовой странице под именем MyControl1
Попробуйте выделить элемент управления и убедитесь, что он не выделяется и добавленные нами свойства не видны в панели Properties. Это значит, что декларативно (в режиме проектирования) из страницы настраивать его нелься, но можно программно управлять (в режиме выполнения) через введенные нами общедоступные свойства, в чем мы и хотим убедиться.
Поместите на страницу под пользовательским элементом управления компонент RadioButtonList из вкладки Standard и убедитесь, что он имеет ID="RadioButtonList1"
Через коллекцию Items элемента RadioButtonList1 задайте три радиокнопки с такими свойствамиText="Красный"; Value="Red"Text="Зеленый"; Value="Green "Text="Синий"; Value="Blue "
Установите свойство 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 сгенерирует нужный
Заполните обработчик RadioButtonList1_SelectedIndexChanged() страницы в файле MyControlTest.aspx.cs следующим кодом(рис ) Код обработчика в файле MyControlTest.aspx.csusing 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, хотя он входит в состав пользовательского элемента управления MyControl1. Взаимодействие страницы с Label1 происходит через добавленные нами в пользовательский элемент управления дополнительные глобальные свойства.Есть еще один способ обеспечить доступ к компонентам,
Поясним сказанное на предыдущем примере.
Скопируйте через панель Solution Explorer, как это мы делали ранее, файл тестовой страницы MyControlTest.aspx и файл пользовательского элемента управления MyControl.ascx
Присвойте копиям новые имена MyControlExtTest.aspx и MyControlExt.ascx соответственно (файлы сопровождающего скрытого кода оболочка переименует автоматически)
Сделайте страницу MyControlExtTest.aspx стартовой, выполнив на ее узле в панели Solution Explorer команду Set As Start Page
Измените параметр Src <%@ Register Src="MyControlExt.ascx" TagName="MyControl" TagPrefix="uc1" %>
Откройте файл скрытого кода MyControlExt.ascx.cs и измените в нем класс MyControl, чтобы он выглядел так(рис ) Добавление в класс пользовательского элемента управления свойства-ссылки на его внутренний компонент Label1 в файле MyControlExt.ascx.csusing 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"
Откройте файл MyControlExtTest.aspx.cs скрытого кода тестовой страницы и отредактируйте его для доступа к прямым свойствам компонента Label1 с использованием созданного адреса InnerLabel1(рис ) Доступ к прямым свойствам Label1 через адрес InnerLabel1 на странице MyControlExtTest.aspxusing 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 MyControlExtTest : 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;
}
}
Выполните страницу и убедитесь, что получился тот же самый результат, что и в предыдущем примере при реализации первого способа
Какой способ выбрать - решать Вам.
На протяжении этой темы мы рассматривали вопрос создания пользовательского элемента управления в режиме проектирования и последующее управление им в программном режиме. Но может потребоваться на странице подгружать и настраивать пользовательский элемент управления динамически ("на лету"). Мы уже программно создавали из библиотечного элемента управления HtmlTable объект-таблицу на странице DynamicTable.aspx. Теперь посмотрим, как это делается для пользовательского элемента управления.
Требуется выполнить следующие шаги:
Page.Load экземпляр класса пользовательского элемента управления, заранее подготовленного в файлах *.ascx и *.ascx.cs. Создание и регистрация экземпляра пользовательского элемента в коде страницы осуществляется Page.LoadControl().PlaceHolder место размещения для точного ID пользовательского элемента управления, особенно, когда создается несколько экземпляров одного и того же элемента. Это может понадобиться для однозначной идентификации элемента в коде страницы при поиске ссылки на экземпляр, выполняемом с помощью статического метода Page.FindControl(), который как раз использует значение идентификатора ID.Есть некоторая специфика динамического создания пользовательского элемента управления. Нельзя создать пользовательский элемент напрямую, как это делается с библиотечным элементом управления через
Скопируйте через панель Solution Explorer, как это мы делали ранее, файл тестовой страницы MyControlExtTest.aspx и файл пользовательского элемента управления MyControlExt.ascx
Присвойте копиям новые имена MyControlDynamicTest.aspx и MyControlDynamic.ascx соответственно (файлы сопровождающего скрытого кода оболочка переименует автоматически)
Сделайте страницу MyControlDynamicTest.aspx стартовой, выполнив на ее узле в панели Solution Explorer команду Set As Start Page
Закройте все предыдущие редактируемые документы командой меню Window/Close All Documents
Откройте на редактирование страницу MyControlDynamicTest.aspx в режиме Design, удалите наш пользовательский элемент управления Label1 и поместите на его место из вкладки Standard стандартный элемент управления PlaceHolder
Перейдите в файле MyControlDynamicTest.aspx в режим Source редактора страницы и удалите полностью старый код <%@ Register Src="MyControlExt.ascx" TagName="MyControl" TagPrefix="uc1" %>
На данном этапе страница в дескрипторном представлении будет такой
<%@ Page Language="C#" AutoEventWireup="true"
CodeFile="MyControlDynamicTest.aspx.cs"
Inherits="MyControlTest" %>
<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. Далее мы программно должны создать этот элемент, добавить ссылку на него к странице, а потом и управлять свойствами его компонентов.
Откройте на редактирование файл скрытого кода
Измените код обработчика 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 MyControlTest : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
// Создаем экземпляр класса поддержки
// пользовательского элемента управления
MyControl MyControl1 = (MyControl)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.
Чаще пользовательский элемент управления проще сделать из обычной страницы .aspx, чем мы и воспользуемся ниже. Это делается так:
@Page вместе с ее атрибутами следует удалить и заменить @Control с требуемыми атрибутами.<html>, <body>, <form>, <head >.Page на UserControl .Control обязательно добавить атрибут ClassName="имя_файла_или_любое_имя". Он извещает ASP.NET, что код, который нужно компилировать, находится в том же файле в дескрипторах <script >. Без этой информации файл компилироваться не будет.Итак, мы разработали несколько пользовательских элементов управления:
Для каждого из этих элементов управления разрабатывалась своя тестовая страница, на которую элемент управления помещался декларативно. Только в последнем случае мы сам пользовательский элемент не изменяли, но на тестовой странице создавали его динамически (программно). Теперь давайте на примере рассмотрим вопрос, когда на страницу нужно поместить программно сразу несколько разных пользовательских элементов управления.
Создайте новую страницу DynamicUserControls.aspx с раздельным кодом и сделайте ее стартовой
В раскрывающемся списке панели Properties выберите элемент DOCUMENT и задайте его свойству Title значение Портальные каркасы
В режиме Design поместите с вкладки Standard элемент Panel и присвойте ему имя Panel1 (оно генерируется автоматически). Этот элемент будет служить контейнером для других элементов управления, в том числе и для пользовательского
Поместите внутрь контейнера Panel1 друг за другом по вертикали стандартные элементыDropDownList с автоматически сгенерированным именем DropDownList1 - для выбора загружаемого в контейнер пользовательского элемента управленияPlaceHolder с автоматически сгенерированным именем PlaceHolder1 - для Label с автоматически сгенерированным именем Label1 - для отображения имени файла, из которого в контейнер загружен пользовательский элемент управленияПо большому счету нам в данном примере безразлично, какие имена будут иметь экземпляры дочерних элементов. Однозначно различать их в коде мы можем по найденным ссылкам. Ссылки, в свою очередь, будем искать в именованном контейнере по типу дочернего элемента, поскольку помещенные нами элементы имеют разный тип. Но сама оболочка Visual Studio 2005 требует, чтобы на странице не было декларативно объявляемых ID.
Проследите в дескрипторном представлении страницы, чтобы ни один из элементов, включая контейнер, не имел атрибутов Width и Height , ограничивающих свободную Заметим, что контейнер Panel1, как родитель, по умолчанию будет определять основные свойства своих дочерних элементов, такие как
Ранее мы перечислили пользовательские элементы управления, которые создали в данной работе. Выберем несколько из них для динамического размещения. Имена этих элементов нужно занести в список DropDownList1. Пусть это будут элементы:
Выделите объект DropDownList1 в контейнере Place1 и заполните декларативно его свойство Items так| Text | Value | |
|---|---|---|
|
(None) | None |
|
HeaderTest.ascx |
|
|
Кнопка 'время-дата' | TimeDisplayTest.ascx |
|
Список гиперссылок | LinkTableTest.ascx |
|
Контролируемый список гиперссылок | LinkTableExtTest.ascx |
|
С настройкой внутренних компонентов | MyControlTest.ascx |
В Value мы указали имена файлов, которые в будущем должны будем создать
Установите для элемента DropDownList1 его свойство AutoPostBack в значение True, чтобы обеспечить постинг страницы при выборе пользователем нужной опцииБудем считать, что один из трех стандартных элементов управления контейнера, а именно список, мы заполнили декларативно. Два других элемента контейнера будем заполнять программно.
Таким образом, один контейнер мы почти настроили. Но мы хотим разместить на странице три таких контейнера, чтобы иметь возможность в каждый из них программно загружать выбранные через список DropDownList1 пользовательские элементы управления. При этом мы хотим убедиться, что они работают независимо друг от друга и каждый делает то, что должен путем реагирования на свои собственные события.
В режиме Design тестовой страницы разместите по вертикали друг за другом три копии контейнера Place1 вместе с его дочерними элементами. Проследите, чтобы контейнеры имели имена Panel1, Panel2, Panel3
Через раскрывающийся список панели Properties выделяйте последовательно каждый контейнер Panel1, Panel2, Panel3 и настройте их свойства такBackColor=Web/GainsboroBorderWidth =1pxHorizontalAlign=CenterBorderStyle =Ridge EnableViewState="False"Мы закончили
<%@ Page AutoEventWireup="true" CodeFile="DynamicUserControls.aspx.cs" Inherits="DynamicUserControls"
Language="C#" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Портальные каркасы</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Panel ID="Panel1" runat="server" BackColor="Gainsboro" BorderStyle="Ridge" BorderWidth="1px"
HorizontalAlign="Center" EnableViewState="False">
<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="LinkTableExtTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
<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="LinkTableExtTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder2" runat="server"></asp:PlaceHolder>
<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="LinkTableExtTest.ascx">Контролируемый список гиперссылок</asp:ListItem>
<asp:ListItem Value="MyControlTest.ascx">С настройкой внутренних компонентов</asp:ListItem>
</asp:DropDownList><br />
<br />
<asp:PlaceHolder ID="PlaceHolder3" runat="server"></asp:PlaceHolder>
<br />
<asp:Label ID="Label3" runat="server" Text="Label"></asp:Label></asp:Panel>
<br />
</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;
}
}
}
Создадим пользовательские элементы управления, которые реализуют пользовательский интерфейс и функциональность, использованную нами при выполнении примеров в тестовых страницах. Из этих тестовых страниц мы их и переделаем.
В панели Solution Explore выделите при нажатой клавише Ctrl следующие файлы
Выполните команду Copy затем Paste (на верхнем узле проекта) контекстного меню
Присвойте копиям те же самые имена, только с расширением .ascx
Откройте новые файлы в дескрипторном режиме и замените @Page на @Control, все остальные атрибуты @Page оставьте прежними. Теперь это будут не страницы, а пользовательские элементы управления. @Register с ее атрибутами оставьте в покое
Удалить из кода все <html>, <body>, <form>, <head > и закрывающие их
Для новых файлов *.ascx откройте файлы скрытого кода *.ascx.cs и замените в объявлении класса имя наследующего класса с " : System.Web.UI.Page " на " : System.Web.UI.UserControl ". Остальной код классов останется прежним.Мы закончили выполнение примера. Код тестовой страницы при очередной загрузке будет программно создавать свои пользовательские элементы управления для каждого контейнера и размещать их в элементах .
Выполните страницу DynamicUserControls.aspx и испытайте ее. Результат будет примерно таким
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.