Расширение функциональности Web контроллеров. Часть 1

  • Автор темы NikSoft
  • Дата начала
N

NikSoft

#1
Пусть мы имеем DataGrid Web контроллер на aspx странице, как показано на рисунке.

DataGrid.jpg

Каждая строка содержит Auto CheckBox, Price TextBox Web контроллеры. Если Auto установлен, то ввод информации в Price запрешен, иначе разрешен. Эта задача решается легко на сервере с помощью события OnCheckedChanged. Но при этом aspx страница перезагружается. Чтобы решить эту проблему на клиенте добавим Java script к Auto CheckBox Web контроллеру.
Создадим новый проект в Visual Studio 2005 типа Class Library с именем CheckBoxNik. Добавим новый тип CheckBoxNik.CheckBox, который наследует из System.Web.UI.WebCotrols.CheckBox, как видно из следующего кода.

Код:
using System;

namespace CheckBoxNik
{
public class CheckBox: System.Web.UI.WebControls.CheckBox
{
string _targetControlID;
const string _addAttribute = "onClick(this, '{0}');";


#region Properties
public string TargetControlID
{
get
{
return _targetControlID;
}
set
{
_targetControlID = value;	
}
}
#endregion

#region Members overrides
protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{

writer.AddAttribute("onClick", String.Format(_addAttribute, TargetControlID));

base.AddAttributesToRender(writer);
}

protected override void OnPreRender(EventArgs e)
{
Page.ClientScript.RegisterClientScriptInclude("CheckBoxNik", Page.ClientScript.GetWebResourceUrl(this.GetType(), "CheckBoxNik.JavaScript.js"));

base.OnPreRender(e);
}
#endregion

}
}
Тип имеет приватное поле – _targetControlID для хранения идентификатора Price контроллера, доступ к которому обеспичивает свойство TargetControlID. Кроме того, добавлены 2 метода AddAttributesToRender, OnPreRender. Первый метод добавляет атрибут ( Java script ) к HTML тэгу “input”, как показано на рисунке.

CheckBox.jpg

Данный атрибут содержит вызов функции onClick, когда мы устанавливаем или сбрасываем Auto Web контроллер. Реализация функции onClick дана в файле JavaScript.js который надо добавить к проекту ( смотри нижеследующий рисунок ).

JavaScript.jpg

Свойство Build Action устанавливаем к Embedded Recource ( обведено синим овалом ). Это позволяет поместить исходный текст функции onClick в ассамблею CheckBoxNik.dll, получающуся в результате построения решения( Build Solution ) данного проекта. Далее помещаем CheckBoxNik.dll в директорию Bin сайта.
Данный Java script будет кэширован браузером при первой загрузке aspx страницы, что сокращает время загрузки последующих вызовов страницы. Функция onClick имеет 2 параметра. В первом передается обьект Auto, в втором - идентификатор Web контроллера Price. Клиентский идентификатор Web контроллера, помещенного в DataGrid, формируется из 3 частей: идентификатора DataGrid Web контроллера, номера строки, в которой находится контроллер, идентификатора самого контроллера. Все три части разделены символом подчеркивания, как например, ItemsGrid_ctl02_AutoCheckBoxID. Зная это, функция onClick вычисляет клиентский идентификатор Web контроллера Price, после чего находим обьект Price. Устанавливаем свойство disabled этого обьекта в зависимости от значения обьекта Auto. Идентификатор Web контроллера Price передается в функцию onClick с помощью свойства TargetControlID, значение которого устанавливается в Auto CheckBox Web контроллере ( смотри нижеследующий код ).

Код:
<datasoft:CheckBox ID="AutoCheckBoxID" TargetControlID="PriceTextBoxID" runat="server" AutoPostBack=false Checked='<%# DataBinder.Eval(Container.DataItem,"auto")%>'/>
Данный контроллер необходимо зарегестрировать в начале aspx страницы ( смотри нижеследующий код ).

Код:
<%@ Register Assembly="CheckBoxNik" Namespace="CheckBoxNik" TagPrefix="datasoft" %>
В второй части статьи я покажу как осуществить доступ к ассамблее CheckBoxNik.dll посредством URL.
 

Вложения

D

Dr.Gigabit

#2
Как насчет генерации JScript кода из C# ? Позволяет практически избавиться от скриптов а программировать подобную логику на более-меннее нормальном языке :blink:
 
P

Pasha

#3
2 Dr.Gigabit: Автор, судя по всему, именно про это и пытается рассказать. Про то, как найти в DOM объекты, соответствующие серверным контролам. И про то, как привязать к ним скриптовые обработчики событий.

Немного непонятно, почему Control переведен как контроллер.
<!--QuoteBegin-NikSoft+31:12:2006, 07:45 -->
<span class="vbquote">(NikSoft @ 31:12:2006, 07:45 )</span><!--QuoteEBegin-->Клиентский идентификатор Web контроллера, помещенного в DataGrid, формируется из 3 частей: идентификатора DataGrid Web контроллера, номера строки, в которой находится контроллер, идентификатора самого контроллера. Все три части разделены символом подчеркивания, как например, ItemsGrid_ctl02_AutoCheckBoxID. Зная это, функция onClick вычисляет клиентский идентификатор Web контроллера Price, после чего находим обьект Price.
[snapback]52144" rel="nofollow" target="_blank[/snapback]​
[/quote]
По теме: а если грид, будет лежать не просто на странице, а внутри, скажем, PlaceHolder-а (или любого другого контрола с интерфейсом INamingContainer)? ClientID у чекбокса не поменяется? И не слишком ли это смело - считать, что механизим генерации "клиентского идентификатора Web контроллера Price" останется тем же в, скажем, .net 4.0.
 
D

Dr.Gigabit

#4
Я несколько не то имел ввиду под генерацией...В примере получается что-то вроде обратного, т.е. привазяка jscript-C# обработчики.

Что касается ClientID -- внутри AjaxControl Toolkint такой же финт ушами делается, причем от хардкондых айдишников в глазах рябит. По опыту -- при переходе от 1.1 к 2.0 были проблемы с подобным трюком :)
 
K

karlito

#5
Для: NikSoft
Код:
Page.ClientScript.RegisterClientScriptInclude("CheckBoxNik", Page.ClientScript.GetWebResourceUrl(this.GetType(), "CheckBoxNik.JavaScript.js"));
Не слишком ли тяжело таскть с собой скриптовый файл?

ItemsGrid_ctl02_AutoCheckBoxID
Мы бУдИм вас убИвать... ХА-ха-ХА...

Для: Dr.Gigabit
касается ClientID -- внутри AjaxControl Toolkint такой же финт ушами делается, причем от хардкондых айдишников в глазах рябит.
убИвать... ХА-ха-ХА...

Я несколько не то имел ввиду под генерацией...В примере получается что-то вроде обратного, т.е. привазяка jscript-C# обработчики.
Ничо не понял. обработчики всё равно остаются клиентские, JavaStript-овые.

Для: Pasha
Немного непонятно, почему Control переведен как контроллер.
Поддерживаю.

Как только страница переходит на поддержку ATLAS Beta 1. Пиши-пропало. Не продашь ты NikSoft свой контрол - работать не будет. Надеюсь, до релиза atlas починят. А пока перуэты в воздухе с тройным подвыпедвертом - на GET запросе регистрируешь скрипт с помощью стандартного ClientScriptManager-а, а на POST регистрируешь этот скрипт с помощь атласовского ClientScriptManager-а. Жаль примера под рукой нет.
 
P

Pasha

#6
<!--QuoteBegin-karlito+10:01:2007, 00:41 -->
<span class="vbquote">(karlito @ 10:01:2007, 00:41 )</span><!--QuoteEBegin-->Не слишком ли тяжело таскть с собой скриптовый файл?
[snapback]52658" rel="nofollow" target="_blank[/snapback]​
[/quote]
Нет, вполне обычная практика. Очень хорошо решает проблемы с подключением кучи скриптов. Тот же atlas так делает....

<!--QuoteBegin-karlito+10:01:2007, 00:41 -->
<span class="vbquote">(karlito @ 10:01:2007, 00:41 )</span><!--QuoteEBegin-->Как только страница переходит на поддержку ATLAS Beta 1. Пиши-пропало. Не продашь ты NikSoft свой контрол - работать не будет. Надеюсь, до релиза atlas починят. А пока перуэты в воздухе с тройным подвыпедвертом - на GET запросе регистрируешь скрипт с помощью стандартного ClientScriptManager-а, а на POST регистрируешь этот скрипт с помощь атласовского ClientScriptManager-а. Жаль примера под рукой нет.
[snapback]52658" rel="nofollow" target="_blank[/snapback]​
[/quote]
Это они вроде почти вылечили в atlas beta2/rc1. По крайней мере, теперь глюки не так часто проявляются.

IMHO, статью следовало бы переименовать в что-то вроде "как связать код JavaScript и серверные элементы управления ASP.NET".
 
P

Pasha

#7
Для: NikSoft
пример (не очень аккуратный, нарисован только для демонстрации)
Код:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Sample Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:DataGrid ID="TestGrid" runat="server" AutoGenerateColumns="false" ShowHeader="false" OnItemDataBound="TestGrid_ItemDataBound">
<Columns>
<asp:TemplateColumn>
<ItemTemplate>
<asp:TextBox ID="textBoxToTarget" runat="server" />
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn>
<ItemTemplate>
<asp:Button ID="buttonToAttachScript" runat="server" Text="Click Me" />
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:DataGrid>
</div>
</form>
</body>
</html>
Код:
// usings here
public partial class _Default : System.Web.UI.Page 
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
TestGrid.DataSource = new int[5];
TestGrid.DataBind();
}
}

private string scriptTemplate = "document.getElementById('{0}').value = 'blah-blah-blah'; return false;";
protected void TestGrid_ItemDataBound(object sender, DataGridItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Control textBoxControl = e.Item.Cells[0].FindControl("textBoxToTarget");
Button button = (Button)e.Item.Cells[1].FindControl("buttonToAttachScript");
button.OnClientClick = String.Format(scriptTemplate, textBoxControl.ClientID);
}
}
}