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

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

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

Основы создания серверных элементов управления. Рисование.

Концепция серверных элементов управления, предложенная Microsoft в ASP.NET, поднимает возможности веб программистов на невиданную доселе высоту. Теперь можно забыть о кропотливом создании отдельных кусков сешанного html/asp кода для решения типовых задач (например вывода данных в таблицу с возможностью сортировки и постраничного вывода) и копирования этих кусков кода в нужные места страниц. Достаточно всего лишь один раз создать класс серверного элемента управления, реализующий данную функциональность и скомпилировать его в сборку и можно использовать получившийся сэлемент управления в любых своих проектах (и даже распространять его дабы и другие программисты могли насладиться его функциональностью :)).

Что же такое серверный элемент управления с точки зрения ASP.NET программиста? Это класс, родителем которого (явным или неявным) является класс System.Web.UI.Control (на самом деле это несколько не так, но для веб программиста данного определения хватит с головой). Данный класс представляет базовую функциональность для элемента управления -например размещение в коллекции серверных элементов управления веб формы и отрисовку. Также он предоставляет функциональность для своего добавления в панель элементов управления и работы в дизайн режиме.

Для создания видимых сервеных элементов управления в основном имспользуется класс System.Web.UI.WebControls.WebControl - наследник класса System.Web.Ui.Control. В этот класс добавлено множество свойств для визуального представления серверного элемента управления (например Font, CssClass, etc), а также добавлена дополнительная функциональность (в том числе и для отрисовки).

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

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

Данный элемент управления представляет собой таблицу, содержащую 3 ячейки для отображения информации о текущей страницы, кнопок для переходов вперед-назад и кнопок для переходов на конкретную страницу. У него есть следующие, нужные при рисовании, свойства:

 

Свойство Описание
PageSize Размер страницы в строках
RowsTotal Строк всего в источнике данных
CurrentPageIndex Текущий номер страницы
CurrentPageFormat Формат для отображения информации о текущей странице (левая ячейка)
 

Начнем создавать класс элемента управления с описания этих свойств:

		private int pageSize = 50;
		private int rowsTotal = 0;
		private int currentPageIndex = 1;
		private string currentPageFormat = "Page {0} of {1}";

		[Bindable(true),
		Category("Data"),
		DefaultValue("50")]
		public int PageSize
		{
			get
			{
				return pageSize;
			}

			set
			{
				pageSize = value;
			}
		}

		[Bindable(true),
		Category("Data"),
		DefaultValue("0")]
		public int RowsTotal
		{
			get
			{
				return rowsTotal;
			}

			set
			{
				rowsTotal = value;
			}
		}

		[Bindable(true),
		Category("Data"),
		DefaultValue("1")]
		public int CurrentPageIndex
		{
			get
			{
				return currentPageIndex;
			}

			set
			{
				currentPageIndex = value;
			}
		}

		[Bindable(true),
		Category("Appearance"),
		DefaultValue("<b>Page</b> {0} of {1}")]
		public string CurrentPageFormat
		{
			get
			{
				return currentPageFormat;
			}

			set
			{
				if(value.IndexOf("{0}") == -1 || value.IndexOf("{1}") == -1)
					throw new ArgumentException("Invalid Current Page Format string");
				currentPageFormat = value;
			}
		}

Так как в данной статье я не рассматриваю вопросы сохранения данных между постбеками и работы с ViewState, то все свойства хранятся в приватных полях класса.

Теперь начнем создания нашего элемента управления. И первые пробы проведем на элементе управления, унаследованном от System.Web.UI.Control. Но для начала немного теории.

Класс System.Web.UI.Control использует при отображении элемента управления три метода и одно свойство. Используемое свойство это ClientID - клиентский дентификатор элемента управления, уникальный в пространстве идентификаторов страницы. Методы же следующие:

 

Метод Описание
public void RenderControl(HtmlTextWriter writer) Проверяет включено ли отображение элемента управления, и если включено - вызывает метод Render
protected virtual void Render(HtmlTextWriter writer) Вызывает метод RenderChildren для отрисовки вложенных элементов управления
protected virtual void RenderChildren(HtmlTextWriter writer) Для каждого элемента управления из коллекции Controls данного элемента управления вызывает его метод RenderControl.
 

В данной таблице приведено описание функциональности, заложенной в эти методы в классе System.Web.UI.Control. При создании элементов управления, напрямую наследуемых от System.Web.UI.Control, для отрисовки необходимо переопределить метод Render. Сделаем это.

Генерация html кода для серверного элемента управления происходит с помощью вызова методов класса HtmlTextWriter.

Первый пример реализации метода Render можно назвать "решением в лоб" - в нем мы будем рисовать нашу таблицу почти так же, как если бы мы рисовали ее с помощью вызовов Response.Write. Никогда не пишите html код элемента управления таким образом - этот кусок кода приведен только для примера!

 
protected override void Render(HtmlTextWriter output)
{ 
	output.Write("<table align=\"center\" width=\"100%\" cellspacing=\"2\" cellpadding=\"2\">");
	int pagesTotal = RowsTotal % PageSize == 0 ? RowsTotal / PageSize : RowsTotal / PageSize + 1;
	output.Write("<tr><td align=\"left\">" + currentPageFormat + "</td>", CurrentPageIndex, pagesTotal);
	output.Write("<td noWrap align=\"center\">");
	if(CurrentPageIndex > 1)
		output.Write("<a href=\"#\"><< Previous</a>&nbsp;&nbsp;");
	if(CurrentPageIndex < pagesTotal)
		output.Write("<a href=\"#\">Next >></a>&nbsp;");
	output.Write("</td>");
	output.Write("<td noWrap align=\"right\">");
	int[,] pageRanges = new int[3, 2] 
		{
			{1, 2},
			{CurrentPageIndex - 2, CurrentPageIndex + 2},
			{pagesTotal - 1, pagesTotal}
		};

	if (pageRanges[0, 1] + 1 >= pageRanges[1, 0])
	{
		if(pageRanges[0, 1] < pageRanges[1, 1])
			pageRanges[0, 1] = pageRanges[1, 1];
		pageRanges[1, 0] = -1000;
	}

	if((pageRanges[1, 0] != pageRanges[1, 1]) && (pageRanges[1,1] + 1 >= pageRanges[2,0]))
	{
		if (pageRanges[2, 0] > pageRanges[1, 0]) 
			pageRanges[2, 0] = pageRanges[1, 0];
		pageRanges[1, 0] = -1000;
	}

	if (pageRanges[0, 1] + 1 >= pageRanges[2, 0]) 
	{
		pageRanges[0, 1] = pageRanges[2, 1];
		pageRanges[2, 0] = -1000;
	}

	output.Write ("<b>Pages:</b>&nbsp;");
	for(int rangeIndex = 0; rangeIndex <= 2; rangeIndex++)
	{
		if(pageRanges[rangeIndex, 0] != -1000) 
		{
			if(rangeIndex != 0) 
				output.Write (".&nbsp;.&nbsp;.&nbsp;");
			int pgIndex = pageRanges[rangeIndex, 0];

			do 
			{
				if(pgIndex == CurrentPageIndex) 
					output.Write(String.Format("<b>{0}</b>&nbsp;", pgIndex.ToString()));
				else
					output.Write("<a href=\"#\">" + pgIndex.ToString() + "</a>&nbsp;");
				pgIndex++;
			}
			while (pgIndex <= pageRanges[rangeIndex,1]);
		}
	}
	output.Write("</td></tr></table>");
}

Описывать логику работы данного метода я думаю нет смысла - все и так достаточно прозрачно. А вот о чем есть смысл поговорить, так это о том, как правильно использовать класс HtmlTextWriter.

Класс HtmlTextWriter представляет с десяток методов для генерации правильного html кода. Наиболее важные для разработчиков серверных элементов управления методы приведены в таблице:

 

Метод Описание
public virtual void RenderBeginTag(HtmlTextWriterTag); Записывает открывающий тег html элемента. Тип тега задается из перечисления HtmlTextWriterTag. Также есть возможность задавать html элемент строкой.
public virtual void RenderEndTag(); Записывает закрывающий тег html элемента. Каждый тег, открытый с помощью вызова метода RenderBeginTag, должен быть закрыт с помощью RenderEndTag
public virtual void AddAttribute(...); Добавляет атрибут в стек. Все добавленные в стек атрибуты присваиваются к первому html элементу, записанному с помощью вызова метода RenderBeginTag.
public virtual void
AddStyleAttribute(...);
Добавляет стилевой атрибут в стек. Все добавленные в стек атрибуты присваиваются к первому html элементу, записанному с помощью вызова метода RenderBeginTag.
public override void Write(...); Записывает значение передаваемого параметра.
 

Теперь попробуем переписать наш метод Render используя приведенную выше таблицу. Должно получиться примерно следующее:

	protected override void Render(HtmlTextWriter output)
	{
		int pagesTotal = RowsTotal % PageSize == 0 ? RowsTotal / PageSize : RowsTotal / PageSize + 1;
		output.AddAttribute(HtmlTextWriterAttribute.Cellspacing, "2");
		output.AddAttribute(HtmlTextWriterAttribute.Cellpadding, "2");
		output.AddAttribute(HtmlTextWriterAttribute.Align, "center");
		output.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%");
		output.RenderBeginTag(HtmlTextWriterTag.Table);
		output.RenderBeginTag(HtmlTextWriterTag.Tr);
		output.AddAttribute(HtmlTextWriterAttribute.Align, "left");
		output.RenderBeginTag(HtmlTextWriterTag.Td);
		output.Write(currentPageFormat, CurrentPageIndex, pagesTotal);
		output.RenderEndTag();
		output.AddAttribute(HtmlTextWriterAttribute.Align, "center");
		output.AddAttribute(HtmlTextWriterAttribute.Wrap, "nowrap");
		output.RenderBeginTag(HtmlTextWriterTag.Td);
		if(CurrentPageIndex > 1)
		{
			output.AddAttribute(HtmlTextWriterAttribute.Href, "#");
			output.RenderBeginTag(HtmlTextWriterTag.A);
			output.Write("<< Previous");
			output.RenderEndTag();
			output.Write("&nbsp;&nbsp;");
		}
		if(CurrentPageIndex < pagesTotal)
		{
			output.AddAttribute(HtmlTextWriterAttribute.Href, "#");
			output.RenderBeginTag(HtmlTextWriterTag.A);
			output.Write("Next >>");
			output.RenderEndTag();
		}
		output.RenderEndTag();
		output.AddAttribute(HtmlTextWriterAttribute.Align, "right");
		output.AddAttribute(HtmlTextWriterAttribute.Wrap, "nowrap");
		output.RenderBeginTag(HtmlTextWriterTag.Td);
		int[,] pageRanges = new int[3, 2] 
			{
				{1, 2},
				{CurrentPageIndex - 2, CurrentPageIndex + 2},
				{pagesTotal - 1, pagesTotal}
			};

		if (pageRanges[0, 1] + 1 >= pageRanges[1, 0])
		{
			if(pageRanges[0, 1] < pageRanges[1, 1])
				pageRanges[0, 1] = pageRanges[1, 1];
			pageRanges[1, 0] = -1000;
		}

		if((pageRanges[1, 0] != pageRanges[1, 1]) && (pageRanges[1,1] + 1 >= pageRanges[2,0]))
		{
			if (pageRanges[2, 0] > pageRanges[1, 0]) 
				pageRanges[2, 0] = pageRanges[1, 0];
			pageRanges[1, 0] = -1000;
		}

		if (pageRanges[0, 1] + 1 >= pageRanges[2, 0]) 
		{
			pageRanges[0, 1] = pageRanges[2, 1];
			pageRanges[2, 0] = -1000;
		}

		output.RenderBeginTag(HtmlTextWriterTag.B);
		output.Write ("Pages:");
		output.RenderEndTag();
		output.Write("&nbsp;");
		for(int rangeIndex = 0; rangeIndex <= 2; rangeIndex++)
		{
			if(pageRanges[rangeIndex, 0] != -1000) 
			{
				if(rangeIndex != 0) 
					output.Write (".&nbsp;.&nbsp;.&nbsp;");
				int pgIndex = pageRanges[rangeIndex, 0];

				do 
				{
					if(pgIndex == CurrentPageIndex) 
					{
						output.RenderBeginTag(HtmlTextWriterTag.B);
						output.Write(pgIndex.ToString());
						output.RenderEndTag();
						output.Write("&nbsp;");
					}
					else
					{
						output.AddAttribute(HtmlTextWriterAttribute.Href, "#");
						output.RenderBeginTag(HtmlTextWriterTag.A);
						output.Write(pgIndex.ToString());
						output.RenderEndTag();
						output.Write("&nbsp;");
					}
					pgIndex++;
				}
				while (pgIndex <= pageRanges[rangeIndex,1]);
			}
		}
		output.RenderEndTag();
		output.RenderEndTag();
		output.RenderEndTag();
	}

Кода стало несколько больше, но преимущества использования данного метода генерации html кода все таки перевешивают. Во первых в результате выполнения этого кода будет получен правильный и "красивый" html код ("красивый" в данном контексте означает отформатированный). А во вторых при генерации html кода элементов управления ASP.NET умеет автоматически подставлять вместо класса HtmlTextWriter его наследников в зависимости от установок в секции <browserCaps> файла machine.config. Например если веб форму запрашивает старый браузер, не понимающий HTML 4.0, класс HtmlTextWriter будет подменен классом HtmlTextWriter32 и будет сгенерирован html, полностью соответствующий спецификации HTML 3.2 (например многие стилевые атрибуты будут заменены на подобные по функциональности html элементы, а вместо элемета div будет использован элемент table). Так что старайтесь писать правильно код генерации html и не гонитесь за мнимой быстротой.

Итак элемент управления создан, рисовать он себя умеет, все красиво, все довольны. Но есть одно большое "но" - нет возможности изенить стили выводимого элемента управления - например поменять шрифт или цвет фона. И все это потому, что класс System.Web.UI.Control предназначен для создания невизуальных элементов управления (например элемента title или xml). А для того, чтобы создавать отображаемые элементы цправления, предназначен класс System.Web.UI.WebControl, уже имеющий базовый набор свойств для стилевого оформления элемента управления. А заодно и расширенный набор методов, отвечающих за отрисовку. Рассмотрим эти методы и свойства:

 

Метод/свойство Описание
public Style ControlStyle {get;} Класс, содержащий свойства стилевого оформления элемента управления
public bool ControlStyleCreated {get;} Свойство, индикатор того, что стиль элемента управления создан.
protected virtual HtmlTextWriterTag TagKey {get;} html тег элемента управления.
protected virtual string TagName {get;} Строка - html тег элемента управления. Используется когда нет соответствующего значения из перечисления HtmlTextWriterTag.
protected virtual Style CreateControlStyle(); Метод создания свойства стилевого оформления документа.
public void ApplyStyle(Style s ); Применяет стиль, указанный в параметре, к элементу управления. При этом из стиля s в стиль элемента управления переносятся все непустые значения, переписывая соответствующие значения в стиле элемента управления.
public void MergeStyle(Style s ); Применяет стиль, указанный в параметре, к элементу управления, но при этом не переписывает существующие значения в стиле элемента управления.
protected virtual void AddAttributesToRender(HtmlTextWriter writer ); Добавляет атрибуты и стили из элемента управления в HtmlTextWriter.
public virtual void RenderBeginTag(HtmlTextWriter writer ); Выводит откывающий html тег для элемента управления
protected virtual void RenderContents(HtmlTextWriter writer ); Выводит содержимое элемента управления (без открывающего и закрывающего html тегов)
public virtual void RenderEndTag(HtmlTextWriter writer ); Выводит закрывающий html тег.
 

Как же WebControl себя рисует с учетом данных нововведений? А достаточно просто - взгляните на код:

protected virtual void Render(HtmlTextWriter writer) {
	RenderBeginTag(writer);
	RenderContents(writer);
	RenderEndTag(writer);
}

public virtual void RenderBeginTag(HtmlTextWriter writer) {

	AddAttributesToRender(writer);
	if (TagKey != HtmlTextWriterTag.Unknown)
		writer.RenderBeginTag(TagKey);
	else
		writer.RenderBeginTag(TagName);
}
protected virtual void RenderContents(HtmlTextWriter writer) {
	base.Render(writer);
}
public virtual void RenderEndTag(HtmlTextWriter writer) {
	writer.RenderEndTag();
}

Как видно из приведенного кода при создании элемента управления из System.Web.UI.WebControls.WebControl для генерации html кода необходимо в общем случае использовать метод RenderContents, а не метод Render. Также при необходимости нужно пеоеопределить свойства TagKey или TagName (по умолчанию WebControl использует тег <span>) или методы RenderBeginTag/RenderEndTag.

Попробуем теперь расширить функциональность отображения нашего элемента управления на основе всего вышеизложенного. И внесем в него следующие изменения:

  1. Добавим работу со стилями, специфичными для отображения таблицы.
  2. Добавим стили для каждой из ячеек элемента управления - ячейки информации, ячейки кнопок "вперед-назад" и ячейки навигационных кнопок.

Итак начем со стилей элемента управления. Первым делом необходимо переопределить метод CreateControlStyle:

		protected override Style CreateControlStyle()
		{
			return new TableStyle();
		}

Теперь необходимо добавить в элемент управления свойства, специфичные для таблицы - CellSpacing, CellPadding и HorizontalAlign. Обратите внимание на то, что эти свойства сохраняются в в свойстве ControlStyle, которое в создаваемом элементе управления имеет тип TableStyle.

	[Bindable(true),
	Category("Appearance"),
	DefaultValue("-1")]
	public
	int CellSpacing {
		get
		{
			if(ControlStyleCreated)
				return ((TableStyle) ControlStyle).CellSpacing; 
			return -1; 
		}
		set
		{
			((TableStyle) ControlStyle).CellSpacing = value; 
		}
	}
	[Bindable(true),

	Category("Appearance"),
	DefaultValue("-1")]
	public int CellPadding {
		get
		{
			if(ControlStyleCreated)
				return ((TableStyle) ControlStyle).CellPadding; 
			return -1; 
		}
		set
		{
			((TableStyle) ControlStyle).CellPadding = value; 
		}
	}
	[Bindable(true),
	Category("Appearance"),
	DefaultValue("NotSet")]
	public HorizontalAlign HorizontalAlign {
		get
		{
			if(ControlStyleCreated)
				return ((TableStyle) ControlStyle).HorizontalAlign; 
			return HorizontalAlign.NotSet; 
		}
		set
		{
			((TableStyle) ControlStyle).HorizontalAlign = value; 
		}
	}

Самое интересное во всем этом коде то, что для его отрисовки ничего больше делать не нужно. При вызове метода WebControl.AddAttributesToRender в нем вызывается метод ControlStyle.AddAttributesToRender, который и выводит все введенные данные.

Теперь добавим свойства для стилей ячеек элемента управления. Эти свойства будут иметь тип TableItemStyle:

	private TableItemStyle infoCellStyle;
	[Bindable(true),
	Category("Style"),
	DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
	PersistenceMode(PersistenceMode.InnerProperty)]
	public TableItemStyle InfoCellStyle
	{
		get
		{
			if (infoCellStyle == null)
				infoCellStyle = new TableItemStyle();
			return infoCellStyle;
		}
	}
	private TableItemStyle prevNextCellStyle;
	[Bindable(true),
	Category("Style"),
	DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
	PersistenceMode(PersistenceMode.InnerProperty)]
	public TableItemStyle PrevNextCellStyle
	{
		get
		{
			if (prevNextCellStyle == null)
				prevNextCellStyle = new TableItemStyle();
			return prevNextCellStyle;
		}
	}
	private TableItemStyle navBtnsCellStyle;
	[Bindable(true),
	Category("Style"),
	DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
	PersistenceMode(PersistenceMode.InnerProperty)]
	public TableItemStyle NavBtnsCellStyle
	{
		get
		{
			if (navBtnsCellStyle == null)
				navBtnsCellStyle = new TableItemStyle();
			return navBtnsCellStyle;
		}
	}

Обратите внимание на то, как правильно нужно объявлять сложные свойства - всегда делайте их "только для чтения". И еще раз напоминаю, что в данной статье мы не рассматриваем сохранение состояние между постбеками, поэтому все свойства сохраняются в приватных переменных класса.

Теперь осталось только сгенерировать html код. Для этого необходимо переопределить свойство TagKey и метод RenderContents. Сделаем это:

	protected override HtmlTextWriterTag TagKey
	{
		get { return HtmlTextWriterTag.Table; }
	}

	protected override void RenderContents(HtmlTextWriter output)
	{
		int pagesTotal = RowsTotal % PageSize == 0 ? RowsTotal / PageSize : RowsTotal / PageSize + 1;
		output.RenderBeginTag(HtmlTextWriterTag.Tr);
		if(infoCellStyle != null)
			infoCellStyle.AddAttributesToRender(output);
		output.RenderBeginTag(HtmlTextWriterTag.Td);
		output.Write(currentPageFormat, CurrentPageIndex, pagesTotal);
		output.RenderEndTag();
		if(prevNextCellStyle != null)
			prevNextCellStyle.AddAttributesToRender(output);
		output.RenderBeginTag(HtmlTextWriterTag.Td);
		if(CurrentPageIndex > 1)
		{
			output.AddAttribute(HtmlTextWriterAttribute.Href, "#");
			output.RenderBeginTag(HtmlTextWriterTag.A);
			output.Write("<< Previous");
			output.RenderEndTag();
			output.Write("&nbsp;&nbsp;");
		}
		if(CurrentPageIndex < pagesTotal)
		{
			output.AddAttribute(HtmlTextWriterAttribute.Href, "#");
			output.RenderBeginTag(HtmlTextWriterTag.A);
			output.Write("Next >>");
			output.RenderEndTag();
		}
		output.RenderEndTag();
		if(navBtnsCellStyle != null)
			navBtnsCellStyle.AddAttributesToRender(output);
		output.RenderBeginTag(HtmlTextWriterTag.Td);
		int[,] pageRanges = new int[3, 2] 
			{
				{1, 2},
				{CurrentPageIndex - 2, CurrentPageIndex + 2},
				{pagesTotal - 1, pagesTotal}
			};

		if (pageRanges[0, 1] + 1 >= pageRanges[1, 0])
		{
			if(pageRanges[0, 1] < pageRanges[1, 1])
				pageRanges[0, 1] = pageRanges[1, 1];
			pageRanges[1, 0] = -1000;
		}

		if((pageRanges[1, 0] != pageRanges[1, 1]) && (pageRanges[1,1] + 1 >= pageRanges[2,0]))
		{
			if (pageRanges[2, 0] > pageRanges[1, 0]) 
				pageRanges[2, 0] = pageRanges[1, 0];
			pageRanges[1, 0] = -1000;
		}

		if (pageRanges[0, 1] + 1 >= pageRanges[2, 0]) 
		{
			pageRanges[0, 1] = pageRanges[2, 1];
			pageRanges[2, 0] = -1000;
		}

		output.RenderBeginTag(HtmlTextWriterTag.B);
		output.Write ("Pages:");
		output.RenderEndTag();
		output.Write("&nbsp;");
		for(int rangeIndex = 0; rangeIndex <= 2; rangeIndex++)
		{
			if(pageRanges[rangeIndex, 0] != -1000) 
			{
				if(rangeIndex != 0) 
					output.Write (".&nbsp;.&nbsp;.&nbsp;");
				int pgIndex = pageRanges[rangeIndex, 0];

				do 
				{
					if(pgIndex == CurrentPageIndex) 
					{
						output.RenderBeginTag(HtmlTextWriterTag.B);
						output.Write(pgIndex.ToString());
						output.RenderEndTag();
						output.Write("&nbsp;");
					}
					else
					{
						output.AddAttribute(HtmlTextWriterAttribute.Href, "#");
						output.RenderBeginTag(HtmlTextWriterTag.A);
						output.Write(pgIndex.ToString());
						output.RenderEndTag();
						output.Write("&nbsp;");
					}
					pgIndex++;
				}
				while (pgIndex <= pageRanges[rangeIndex,1]);
			}
		}
		output.RenderEndTag();
		output.RenderEndTag();
	}

Приведенный код не очень сильно отличается от кода метода Render, рассмотренного в предыдущем примере. Таких отличий всего 2:

  1. Не вызывается метод для генерации тега table (этот тег генерится в методах RenderBeginTag и RenderEndTag на основании значения свойства TagKey.
  2. При генерации тегов td к ним добавляются соответствующие стили с помощью вызовов их методов AddAttributesToRender.

Все. Последняя (и наиболее правильная) версия рисования серверного элемента управления Pager готова. Конечно есть и еще один вариант создания этого метода - с помощью заполнения коллекции Controls элемента управления, но это тема для отдельной статьи.

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


Текст примеров данной статьи можно выкачать здесь


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


Автор: Dmytro Rudenko
Прочитано: 3053
Рейтинг:
Оценить: 1 2 3 4 5

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

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

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