Основы ASP.NET 2.0

         

Атрибуты


Наличие атрибутов — важное свойство языков .NET. С их помощью в метаданные класса в сборку добавляется информация, которая используется самым различным образом. Атрибуты — это классы, наследующие System.Attribute и применяющиеся к пространствам имен, классам, свойствам и методам. Синтаксис применения атрибута в C#:

[CustomAttr(Update:=true, Keep=false)]

Конструктор атрибута указывается в квадратных скобках с параметрами, которые определены в декларации класса атрибута.

В ASP .NET атрибуты в том числе определяют поведение пользовательских элементов управления (а также, например, используются в описании web-сервисов). В описании WebCustomControl1 атрибуты применены и к самому классу, и к свойству Text. Атрибуты класса определяют его помещение в панель Toolbox и в дизайнере страниц. Их можно поделить на 3 категории: атрибуты, помогающие среде разработки работать с элементом управления в режиме дизайна; атрибуты, управляющие выводом дочерних элементов; атрибуты, определяющие его поведение в панели инструментов.

DefaultProperty определяет свойство по умолчанию. При открытии окна свойств элемента управления в дизайнере помеченное этим атрибутом свойство будет выделено бежевым.

ToolboxData задает форматирующую строку. Например,

ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")

Это строка с формальным параметром, в качестве значения которого подставляется атрибут TagPrefix директивы Register, регистрирующей данный элемент на конкретной странице.


Когда в дизайнере страницы происходит двойной щелчок мыши на элементе, среда разработки создает обработчик события, например, SelectedIndexChanged для выпадающего списка DropDownList. Какое именно событие, определяется атрибутом DefaultEvent.

Атрибуты применяются также к свойствам и событиям элемента.

Bindable указывает, что свойство можно связать с источником данных.

Category обозначает категорию в окне свойств элемента. Свойства разбиваются на категории, если выбрать представление Categorized окна свойств.

Атрибут Themable определяет, может ли данное свойство определяться в файле скина.

По умолчанию ASP .NET позволяет всем свойствам написанных нами элементов управления быть описанными в файлах скинов. Это не всегда удобно, если свойство не относится к внешнему виду элемента. В таком случае атрибут создается с параметром false:

[Themeable(false)] public string Text

Browsable указывает, будет ли отображаться свойство в окне свойств, и EditorBrowsable — возможно ли будет его редактировать.

Существуют и другие атрибуты.


Отрисовка (Rendering) элемента управления


В этом примере построен элемент управления, наследующий от Label. Он раскрашивает текст в случайные цвета. Свойство EnableRainbowMode можно отключить, тогда он станет вести себя как обычная метка:

[ToolboxData("<{0}:RainbowLabel runat=server></{0}:RainbowLabel>")] public class RainbowLabel : Label { [Bindable(true)] [Category("Appearance")] [DefaultValue("true")] [Localizable(true)] public bool EnableRainbowMode { get { if (ViewState["EnableRainbowMode"] == null) return true; else return bool.Parse(ViewState["EnableRainbowMode"].ToString()); } set { ViewState["EnableRainbowMode"] = value; } }

protected override void RenderContents(HtmlTextWriter output) { if(EnableRainbowMode) output.Write(ColorizeString(Text)); else output.Write(Text); } private string ColorizeString(string input) { StringBuilder output = new StringBuilder(input.Length); Random rand = new Random(DateTime.Now.Millisecond);

for (int i = 0; i < input.Length; i++) { int color = rand.Next(0xffffff); string strColor = string.Format(@"<span style=""color: #{0:x}"">", color); output.Append(strColor); output.Append(input.Substring(i, 1)); output.Append("</span>"); } return output.ToString(); } }



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


Мы познакомились с большим количеством встроенных в ASP.NET элементов управления.

Хотя набор стандартных элементов велик — всегда может понадобиться такой элемент, которого в стандартной поставке нет. Или есть страница с такой функциональностью, которую хочется использовать и на других страницах. Можно, конечно воспользоваться клеем и ножницами (Copy-Paste), но сущность объектно-ориентированного и компонентного программирования — в повторном использовании кода, заключенного в готовые компоненты. Следовательно, нужно научиться создавать собственные элементы управления.

Пользовательские элементы управления инкапсулируют несколько готовых элементов в одном контейнере, который можно повторно использовать в проекте. Они наследуются от класса UserControl — наследника класса Control. Пользовательские элементы компилируются точно так же, как и страницы aspx.

Серверные элементы, кроме этого, реализуют собственное поведение и самостоятельно выводят HTML-код, который их отображает. Они могут наследоваться от WebControl или одного из классов стандартных элементов управления. Их можно использовать в любых проектах и распространять в виде откомпилированной PE (Portable Executable) сборки.

Мы знаем, что класс Page наследует класс Control, как и все элементы управления, некоторые прямо, а другие через класс WebControl или HtmlControl. Следовательно, между написанием страницы и разработкой собственного элемента управления должно быть много общего. У них тоже есть свой жизненный цикл. В классе Control определены события Init, Load, DataBinding, PreRender, Unload, Disposed.




Свойства, которые Control предоставляет своим наследникам, включают EnableViewState, ID, UniqueID, Page, Parent, SkinID, ViewState и Controls — коллекция дочерних элементов управления.

Класс Control предоставляет возможность помещать элемент управления в дерево элементов управления, которые отображаются на странице .aspx. Класс Control также реализует интерфейс System.ComponentModel. IComponent, который делает компонент конструктивным. Конструктивный компонент может быть добавлен в панель Toolboox визуального дизайнера, может быть помещен на разрабатываемую страницу методом drag-and-drop, может отображать свойства в окне свойств и обеспечивать другие виды поддержки режима разработки (в том числе Smart Tags).

Пользовательские элементы управления можно создавать в визуальном редакторе по той же модели, что и страницы aspx. Как всегда, откроем диалог NewFile и выберем тип страницы Web User Control. Расширение файла с дизайном элемента — ascx, а с кодом класса — ascx.cs. В отличие от страниц aspx, сам по себе пользовательский элемент нельзя увидеть в браузере, для этого он должен находиться на какой-нибудь странице:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %>

Как упоминалось в лекции 2, директива Control — это аналог директивы Page для элемента управления. На странице не указываются теги <html> и <body>, потому что содержание элемента включается в код страницы, в котором он содержится.



Изначально в элементе вообще нет никаких тегов.

Класс пользовательского элемента управления — наследник System.Web.UI.UserControl. В остальном он ничем не отличается от файла с классом страницы:

public partial class WebUserControl : System.Web.UI.UserControl { }

Можно добавить в него любые элементы управления и HTML-код:

<h1><%= Greeting %>, <%= Name %>!</h1> <asp:TextBox ID="txtName" runat="server"></asp:TextBox><br /> <asp:Button ID="btnClick" runat="server" Text="Button" />

В классе элемента управления определим его свойства:

string name; string greeting; public string Greeting { get { return greeting; }

set { greeting = value; } } public string Name { get { return name; }

set { name = value; } }

protected void Page_Init(object sender, EventArgs e) { btnClick.Text = "Enter your name and click"; }

При нажатии на кнопку свойства элемента заполняются данными из текстового поля:

protected void btnClick_Click(object sender, EventArgs e) { Name = txtName.Text; }

Теперь перетащите название элемента из Solution Explorer на любую страницу.

Чтобы использовать пользовательский элемент на странице, его надо зарегистрировать. Директива Register появляется автоматически:

<%@ Register Src=" WebUserControl.ascx" TagPrefix="User" TagName="GreetingControl" %>



Его значение может быть любым, кроме asp, которое зарезервировано для встроенных элементов управления ASP .NET. TagName — это имя элемента, идущее после префикса; атрибут Src определяет путь к файлу пользовательского элемента управления.

Теперь новый пользовательский элемент управления можно описать так:

<User:GreetingControl id="Hello" runat="server" Name="Heinrich" Greeting="Guten Tag"/>

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

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

В коде страницы можно манипулировать его свойствами:

protected void Page_Load(object sender, EventArgs e) { Hello.Greeting = "Привет"; }

Пользовательский элемент может получить доступ к странице, в которой находится, через свойство Parent. Если в родительскую форму добавить TextBox, он может прочитать его значение и использовать его:

<asp:TextBox ID="txtGreeting" runat="server"></asp:TextBox><br /> <User:GreetingControl id="Hello2" runat="server" Name="Heinrich" Greeting="Guten Tag" OnLoad="Hello2_Load"/>

protected void btnClick_Click(object sender, EventArgs e) { Name = txtName.Text; TextBox tb=Parent.FindControl("txtGreeting") as TextBox; if ( tb!= null) { Greeting = tb.Text; } }



Только что созданный элемент управления можно даже добавить в панель инструментов, и перетаскивать оттуда на любую страницу. Но директиву Register придется добавлять самим.

Можно попробовать создать WebUserControl в событии Page_Load, но это не даст результата. Причина в том, что класс объявлен лишь частично в файле отделенного кода, в нем не хватает функции отрисовки, которая появится при обработке страницы ascx ASP .NET.

Чтобы программно создать экземпляр пользовательского элемента управления, нужно вызвать функцию LoadControl, который вернет экземпляр класса System.Web.UI.Control, содержащий загружаемый элемент управления. Чтобы иметь доступ к свойствам класса WebUserControl, нужно преобразование типа. И, как и всякий другой элемент управления, загруженный пользовательский элемент управления может быть добавлен в коллекцию элементов управления web-формы. Его нельзя добавить в страницу, так как его составной частью является кнопка, которая может находиться только в форме:

WebUserControl wuc = (WebUserControl)Page.LoadControl("WebUserControl.ascx"); wuc.Greeting = "Здоровеньки булы"; wuc.Name = "Тарас"; form1.Controls.AddAt(0, wuc);

Более полезный пользовательский элемент управления — нижний колонтитул любой страницы. Его можно поместить на шаблон дизайна. Он может отобразить юридическую информацию, адрес web-мастера и дату последнего обновления:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Footerl.ascx.cs" Inherits="Footerl" %> Copyright &copy; <asp:Label ID="lblYear" runat="server" /> by Your Company Name.<br />

Замечания, комментарии, проблемы? Свяжитесь с web-мастером <asp:Label ID="lblEmail" runat="server" /><br /> Дата последней модификации этой страницы: <asp:Label ID="lblLastMod" runat="server" /><br />

Текст в элементах Label меняется в обработчике Page_Load.

protected void Page_Load(object sender, EventArgs e) { lblYear.Text = DateTime.Now.Year.ToString(); lblEmail.Text = "<a href='mailto:webmaster@" + Request.Url.Host.Replace("www.", "") + "'>webmaster</a>"; lblLastMod.Text = System.IO.File.GetLastWriteTime(Server.MapPath(Request.Url.LocalPa th)).ToLongDateString(); }


Серверные элементы управления


Серверные элементы управления, унаследованные от WebControl или Control, сложнее создавать, но у них еще больше возможностей. Такие элементы имеют собственные методы генерации HTML-кода. Сложность в том, что здесь класс полностью описывается программистом, без визуального дизайна и файла ascx. В классе WebControl определены визуальные свойства, такие как BackColor, Font, ToolTip. В них можно определить сложную логику пользовательского интерфейса. Если элемент управления не нуждается в таких свойствах, его нужно наследовать от Control. При этом он генерирует HTML-код, например теги <meta> или скрытые элементы.

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

Серверные элементы управления помещаются в библиотеки WebControls. Чтобы создать библиотеку, в меню File выберите New Project, и в появившемся диалоге — тип проекта Web Control Library (он находится в узле Visual C#-Windows). В проекте уже создан простейший серверный элемент управления. Библиотеку можно создать только в Visual Studio, а в VWD — только класс в папке App_Code:

namespace WebControlLibrary1 { [DefaultProperty("Text")] [ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")] public class WebCustomControl1 : WebControl { [Bindable(true)] [Category("Appearance")] [DefaultValue("")] [Localizable(true)] public string Text { get { String s = (String)ViewState["Text"]; return ((s == null) ? String.Empty : s); }


set { ViewState["Text"] = value; } }

protected override void RenderContents(HtmlTextWriter output) { output.Write(Text); } } }

У этого элемента всего одно свойство Text, и он просто записывает в поток вывода страницы HTML значение этого свойства.

Если в решении есть проект с библиотекой пользовательских элементов, они автоматически добавляются в инструментальную панель (Toolbox). Для этого достаточно всего лишь скомпилировать проект. В папке Bin появляется WebControlLibrary1.dll. Это сборка, в которой находятся все элементы управления библиотеки.

Если вы работаете не с Visual Studio, все равно можно откомпилировать классы в сборку .dll из командной строки1).

csc /t:library /out: WebControlLibrary1.dll /r:System.dll /r:System.Web.dll *.cs

В панели инструментов появится новая секция со значками-шестеренками, и элементы управления можно перетаскивать оттуда на страницы.

Директива Register, которая автоматически добавляется, будет содержать название этой сборки и пространство имен, в котором находится элемент управления:

<%@ Register Assembly="WebControlLibrary1" Namespace="WebControlLibrary1" TagPrefix="cc1" %>

Чтобы не писать одну и ту же директиву на многих страницах, библиотеку можно зарегистрировать в файле web.config.

У созданного элемента, кроме свойства Text, есть все свойства внешнего вида и поведения, как у стандартных элементов управления, как вы можете убедиться, открыв его окно свойств. Он очень похож на элемент Label.

Доступ к сборке WebControlLibrary1.dll можно предоставить всем приложениям, если поместить ее в глобальный кэш сборок.


Составные элементы управления


Составные элементы управления наследуются от класса Composite Control. Этот элемент представляет собой объединение текстовой строки с валидатором, который проверяет ее значение на соответствие шаблону адреса электронной почты. EnsureChildControls — это метод, который проверяет, существуют ли вложенные элементы. Если нет, вызывается метод CreateChildControl: [DefaultProperty("Text")]

[ToolboxData("<{0}:EmailTextBox runat=server></{0}:EmailTextBox>")] public class EmailTextBox : CompositeControl, INamingContainer { private TextBox textBox; private RegularExpressionValidator validator; [Bindable(true)] [Category("Appearance")] [DefaultValue("")] [Localizable(true)] [Themeable(false)] public string Text { get { EnsureChildControls(); return textBox.Text; } set { EnsureChildControls(); textBox.Text = value; } } [Themeable(false)] public string ErrorMessage { get { EnsureChildControls(); return validator.ErrorMessage; } set { EnsureChildControls(); validator.ErrorMessage = value; } } public override ControlCollection Controls { get { EnsureChildControls(); return base.Controls; } } protected override void CreateChildControls() { Controls.Clear();

textBox = new TextBox(); validator = new RegularExpressionValidator();

Controls.Add(validator); Controls.Add(textBox);

textBox.ID = "Email1"; validator.ControlToValidate = textBox.ID; validator.ValidationExpression=@"\w+([-+.']\w+)*@\w+([ -.]\w+)*\.\w+([-.]\w+)*"; } }

У элемента управления EmailTextBox имеются свойства Text и ErrorMessage, которые можно определять на страницах aspx.

<cc1:EmailTextBox ID="EmailTextBox1" runat="server" Text="Hello" ErrorMessage="Адрес E-mail неправильный!"/>



и собственные серверные элементы управления


Пользовательские и собственные серверные элементы управления — это реализация в ASP .NET передовой концепции компонентного программирования. Они облегчают повторное использование кода.