Исходники.Ру - Программирование
Исходники
Статьи
Книги и учебники
Скрипты
Новости RSS
Магазин программиста

Главная » Статьи по программированию » .NET - ASP.NET »

Обсудить на форуме Обсудить на форуме

ASP.NET - повторное использование кода для построения пользовательского интерфейса

Программирование Web приложений, с точки зрения повторного использования кода для построения пользовательского интерфейса, всегда отставало от возможностей при программировании GUI приложений. Повторное использование кода в ASP ограничивалось несколькими основными подходами:

  • Использование включаемых (include) скриптов
    Пожалуй, самый распространенный метод. При нарастании сложности пользовательского интерфейса задача поддержки и развития библиотеки скриптов становится трудно выполнимой. Отсутствует поддержка со стороны среды визуального проектирования. Из-за необходимости включать в каждую страницу большое количество дополнительных скриптов, время интерпретации при обработке запроса к странице могло достигать неприемлемых величин.
  • использование COM объектов
    Ограниченность и сложность взаимодействия контекста интерпретируемой ASP страницы с вызываемым COM объектом. Проблема блокировки DLL, в которых реализованы COM объекты, усложняет задачу администрирования Web сервера.
  • Web Class проекты.
    Позволяют отделять код от разметки страницы. Создавая HTML шаблоны и WebClass проекты в Visual Basic 6.0 для их обработки, разработчик работал в привычной модели событийного программирования. В некотором смысле являются прообразом подходов в ASP.NET, о которых мы будем говорить дальше в статье.

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

ASP.NET предлагает новый подход с использованием пользовательских серверных элементов управления (Custom Control). Компонент, реализующий серверный элемент управления запускается на Web сервере, и, в общем случае, не предъявляет каких-либо требований к клиенту (HTML обозревателю). Собственные серверные элементы управления могут формировать представление от HTML, до использования сложных клиентских скриптов и XML. Существует несколько вариантов создания собственных серверных элементов управления для построения пользовательского интерфейса, отличающихся по своим возможностям. Программист, начинающий разработку на ASP.NET, зачастую затрудняется в правильном выборе типа компоненты, которая оптимально подходит для его задачи и теряется в терминологии. В первой части статьи я не буду подробно останавливаться на деталях использования (подробный обзор по серверным элементам представлен Надеждой Шатохиной: Разработка серверных элементов управления ASP.NET ), а рассмотрю категории собственных серверных элементов управления именно с точки зрения области их применения. Во второй части статьи мы рассмотрим прием, который позволяет облегчить создание так называемых Composite Control.

 

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

  • Первый подход, по которому предлагается идти разработчику - использовать Web User Controls. При этом подходе разработчик создает комплексные объекты пользовательского интерфейса в виде отдельных Web Form и затем с минимальными усилиями преобразует их в Web User Controls. Далее Web User Controls могут быть использованы на ASPX странице как единый объект. Web User Control наследуются из System.Web.UI.UserControl. Как и Web Forms страницы, Web User Controls компилируются на лету, при обработке первого запроса, и сохраняются в памяти для снижения времени обработки последующих запросов. При этом Web User Controls предоставляют те же возможности по разделению языка разметки страницы от кода пользовательского интерфейса (подход Code Behind), что и Web Forms. Разработчик использует визуальные дизайнеры форм и code behind классы при разработке самого Web User Control. Визуальный дизайнер Web User Control предоставляет те же возможности, что и дизайнер Web Form. Но в дальнейшем, при внедрении Web User Control на Web Form-у, поддержка визуального дизайнера крайне ограничена. Web User Control может кэшироваться независимо от содержащий его страницы. Такая техника называется фрагментарным кэшированием и поддерживается инфраструктурой Web Forms.
    Пожалуй, самое главное ограничение, связанное с Web User Control заключается в невозможности разделять один Web User Control между несколькими Web приложениями (даже в рамках одного Web сервера). Web User Control должен располагаться в подкаталогах корневого каталога Web приложения. И если вы хотите повторно использовать Web User Control в нескольких приложениях, Вам ничего не остается, как копировать их в подкаталоги этих приложений - со всеми вытекающими отсюда последствиями. Таким образом, этот подход в основном применяют для повторного использования элементов пользовательского интерфейса в рамках одного Web приложения.
  • Второй подход условно можно определить как разработку элемента управления в виде компилированной сборки. Такие элементы носят общее название Custom Web Controls. При этом подходе элемент управления компилируется в сборку и устанавливается либо в подкаталог bin web приложения, либо в глобальный кэш сборок. В последнем случае элемент управления может быть внедрен на ASPX страницы любого приложения на Web сервере. Каждый Custom Web Controls программируется в виде отдельного объекта, наследуемого из System.Web.UI.WebControls.WebControl или System.Web.UI.Control. При этом Visual Studio.NET не предоставляет разработчику дизайнеров графического интерфейса и возможности использовать сочетания страниц с разметкой вывода в HTML с code-behind файлами классов. С Custom Web Control программист реализует последующее HTML представление своего элемента исключительно в коде. Таким образом, Custom Web Control, с одной стороны дают большую гибкость с точки зрения генерации визуального представления элемента и использования его несколькими приложениями, а с другой стороны требуют более значительных, по сравнению с User Web Controls, усилий по разработке. Для последующего использования в формах web приложения, разработчик может обеспечить для своего Custom Web Control поддержку в визуальном дизайнере форм.

    Давайте детальнее посмотрим, для решения, каких задач, подходят Customs Web Controls.

    • Вас устраивают User Web Controls с точки зрения возможности комбинирования стандартных элементов управления ASP.NET для построения .повторно используемого пользовательского интерфейса. Но Вы хотите повторно использовать Ваш элемент в нескольких приложениях в рамках web сервера. В этом случае Вы обратитесь к так называемым Composite Control
    • Существующий серверный элемент управления ASP.NET практически полностью удовлетворяет Вашим требованием за исключением небольших особенностей. В этом случае Вы можете прямо наследовать класс своего Custom Server Control из этого стандартного элемента.
    • Ни один из серверных элементов управления ASP.NET или их комбинация не удовлетворяет Вашим требованиям. Тогда Вы обращаетесь к так называемым Rendering Control, который позволяют Вам полностью управлять поведением Вашего элемента и его представлением в ASPX странице - контейнере.

 

Помимо этих категорий применяются термины для обозначения подкатегорий элементов управления, связанных с использованием некоторых возможностей инфрастуктуры страниц ASP.NET. Имеются ввиду Templated Control и Templated Data-Bound Control. Templated Control позволяют создавать элемент управления таким образом, что бы разработчик, использующий его на ASPX странице мог настраивать его представление через использование шаблонов (Подобно DataRepeater. DataGrid и т.п.) . Templated Data-Bound Control помимо этого позволяет связывать такие шаблоны для представления UI с коллекциями данных.

Реализация Composite Control

Сделав небольшой обзор типов Controls, давайте обратимся к Composite Controls. Они занимают промежуточное положение между User Controls, когда представление формируется из представлений нижележащих элементов, и Rendering Controls ,когда Вы полностью формируете представление Вашего элемента.

Рассмотрим на примере. Наш Composite Control будет состоять из Textbox , двух Label , и Button и реализовывать интерфейс для поиска Имени и Фамилии сотрудника по его уникальному номеру. При нажатии на кнопку наш Control будет осуществлять поиск информации о сотруднике по его номеру, устанавливать свойства Text двух Label в значение Имени и Фамилии, генерировать собственное событие. Дополнительно он будет реализовывать свойства двух TextBox как свои свойства. При разработке Composite Control нужно учитывать следующее:

  • Подчиненные элементы управления необходимо создавать в CreateChildControls методе, а не в конструкторе или методе OnInit
  • Composite Control реализует интерфейс INamingContainer для правильной маршрутизации postback события к его подчиненному элементу управления ( в нашем случае - Button )
  • Composite Control не распространяет событие Click подчиненного элемента. Вместо этого он перехватывает событие и генерирует собственное событие Find.

Пример реализации Composite Control:

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;

namespace CustomControls 
{
public class Composite : Control, INamingContainer 
{
	private Label lblFirstName;
	private Label lblLastName;
	private TextBox txtID;
            
	public string LastName
	{
		get
		{
//	необходимо убедиться, что подчиненные контролы существуют. В противном 
//	случае они будут созданы			
EnsureChildControls();
			return lblLastName.Text;
		}
	}
	public string FirstName
	{
		get
		{
			EnsureChildControls();
			return lblFirstName.Text;
		}
	}
            
// Событие, генерируемое Composite Control при нажатии на подчиненную кнопку
	public event FindEventHandler Find;
	            
	protected virtual void OnFind(FindEventArgs fe)
	{
		if (Find != null)
		{
			Find(this,fe);
		}
	}
// переопределяем метод CreateChildControls() для формирования коллекции 
// подчиненных элементов управления, участвующих в формировании HTML 
// представления. При этом не нужно реализовывать метод Render(), поскольку
//  подчиненные элементы полностью управляют выводом
	            
	protected override void CreateChildControls() 
	{
	                  
		Controls.Add(new LiteralControl("<h3>введите номер : "));
		                  
		txtID = new TextBox();
		txtID.Text = "0";
		Controls.Add(txtID);
		                  
		Controls.Add(new LiteralControl("</h3>"));
		                  
		Button button1 = new Button();
		button1.Text = "Найти";
		Controls.Add(new LiteralControl("<br>"));
		Controls.Add(button1);
		button1.Click += new EventHandler(this.ButtonClicked);
		                  
		Controls.Add(new LiteralControl("<br><br>"));
		lblFirstName = new Label();
		lblFirstName.Height = 50;
		lblFirstName.Width = 500;
		Controls.Add(lblFirstName);

		Controls.Add(new LiteralControl("<br>"));
		lblLastName = new Label();
		lblLastName.Height = 50;
		lblLastName.Width = 500;
		Controls.Add(lblLastName);
	                  
	}            
	private void ButtonClicked(Object sender, EventArgs e)
	{
		bool found = false;
		int id;
		try
		{
			id = Int32.Parse(txtID.Text);
		}
		catch(Exception ex)
		{
			id = -1;
		}
		if( id == 1 )
		{
			found = true;
			lblFirstName.Text = "Dmitry";
			lblLastName.Text  = "Starostin"; 
		}
		else
		{
			lblFirstName.Text = "";
			lblLastName.Text  = ""; 
		}
//	генерируем событие для обработки в Web форме
		OnFind(new FindEventArgs(found));
	}
}
public class FindEventArgs : EventArgs
{
	private bool _found = false;
	public FindEventArgs (bool found)
	{
			_found = found;
	}
	public bool Found
	{
		get
		{
			return _found;
		}
	}
}
// делегат, используемый для объявления события       
public delegate void FindEventHandler(object sender, FindEventArgs fe);
}

Так будет выглядеть ASPX страница для формы, содержащей наш Composite Control. Для наглядности, код включен в ASPX страницу и подход code behind не используется.

 

<%@ Page language="c#"  AutoEventWireup="false" %>
<%@ Register TagPrefix="cc1" Namespace="CustomControls" Assembly="WebControlLibrary1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
  <HEAD>
	<title>WebForm1</title>
	<meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
	<meta name="CODE_LANGUAGE" Content="C#">
	<meta name="vs_defaultClientScript" content="JavaScript">
	<meta name="vs_targetSchema"   content="http://schemas.microsoft.com/intellisense/ie5">
	<script language="C#" runat="server">

      private void ShowInfo (Object sender,FindEventArgs e)
      {
      	if (e.Found==true)
		{
		Label1.Text	= Composite1.FirstName + "  " + Composite1.LastName ;
		}
		else
		{
		Label1.Text	= "сотрудник не найден :(";
		}
	}           
      </script>
   </HEAD>
   <body>
	<form id="Form1" method="post" runat="server">
	<P>
  	 <asp:Label id="Label1" runat="server" Width="246px" Height="13px"></asp:Label>
      </P>
	<P>
	 <cc1:Composite id="Composite1" OnFind="ShowInfo" runat="server"></cc1:Composite></P>
	</P>
	</form>
	</body>
</HTML>

Таким образом, Composite Control предоставляет практически те же возможности по построению пользовательского интерфейса, что и Web User Control. Мы получаем откомпилированный элемент, который, после установки в GAC, можем использовать в любых ASP.NET приложениях на сервере. При этом мы воспользовались возможностями подчиненных элементов управления для формирования визуального интерфейса. Что нам не хватает, так это возможности использовать визуальный дизайнер Web Forms в Visual Studio.NET для работы с Composite Control, подобно тому, как мы работаем с Web User Control.

Использование дизайнера форм для создания Composite Control

Внимательный читатель укажет на то, что в начале статьи подчеркивалась возможность использования визуального дизайнера ТОЛЬКО для Web User Control. Реализация метода CreateChildControls() для Composite Control, в котором динамически создаются ВСЕ подчиненные элементы и задаются их свойства, становится трудоемкой с увеличением сложности интерфейса. Давайте попробуем найти пути обхода этого недостатка. Как мы знаем, ASP.NET при обработке запросов обеспечивает компиляцию на лету ASPX страниц и Code Behind кода. Легко предположить, что представление, задаваемое разметкой HTML в ASPX странице, будет сформировано через последовательность создания контролов ASP.NET и вызовов соответствующих методов на них. Давайте попробуем воспользоваться результатами работы инфраструктуры ASP.NET .

  • Создадим в дизайнере VS.NET новую Web форму
  • Разработаем в дизайнере, добавляя элементы управления и выставляя их свойства, точное визуальное представление, которое мы хотим получить в дальнейшем от Custom Control.
  • Выполним обращение к этой форме из браузера
  • Исходя из нашего предположения, ASP.NET должен был разобрать ASPX файл и сформировать соответствующие классы. Сделаем еще одно предположение, что результаты своей работы ASP.NET сохраняет во временных файлах. Обратимся к директории
  • <%Net Framework%\<version>\Temporary ASP.NET Files> и увидим поддиректории с названиями проектов последних используемых Web приложений. Спустившись в поддиректории каталога нашего приложения, найдем несколько временных файлов с расширениями используемого языка программирования ( в нашем случае - CS). Просмотрев содержимое этих файлов легко найти использованные идентификаторы элементов управления.
  • Воспользуемся результатами работами парсера ASP.NET. Свернем в редакторе VS.NET сгенерированный класс из временного файла к описаниям методов и свойств. Скопируем в исходный код нашего Composite Control определения подчиненных элементов управления и все методы, начинающиеся с префикса __Build. Именно в этих методах и происходит генерация дерева подчиненных элементов управления.

  • Осталось в методе CreateChildControls нашего Composite Control вызвать _BuildControlTree и добавить обработчик события нажатия кнопки.
    	protected override void CreateChildControls() 
    	{
    		this.__BuildControlTree(this);
    		Button1.Click += new EventHandler(this.ButtonClicked);
    	}
    

    Мы получили Composite Control, проектируя его визуальное представление в дизайнере Web форм. Мы придерживались этой последовательности действий:

    1. Разработка визуального представления в дизайнере Web Form
    2. Копирование из временных файлов с исходным текстом в файл с классом Composite Control определений всех подчиненных элементов управления и методов для их инициализации
    3. добавление всех обработчиков событий в CreateChildControls после вызова _BuildControlTree

Видно, что и в дальнейшем мы сможем менять визуальное представление в дизайнере форм и используя показанный прием для модификации кода реализации класса Composite Control. И нет необходимости писать реализацию CreateChildControls вручную! Мы совместили удобство создания User Web Controls с большей гибкостью Composite Control.


Может пригодится:


Автор: Дмитрий Старостин
Прочитано: 5242
Рейтинг:
Оценить: 1 2 3 4 5

Комментарии: (0)

Добавить комментарий
Ваше имя*:
Ваш email:
URL Вашего сайта:
Ваш комментарий*:
Код безопастности*:

Рассылка новостей
Рейтинги
© 2007, Программирование Исходники.Ру