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

Тема в разделе ".NET", создана пользователем NikSoft, 31 дек 2006.

Наш партнер Genesis Hackspace
  1. NikSoft

    NikSoft Гость

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

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

    Каждая строка содержит 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, как видно из следующего кода.

    Код (Text):
    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”, как показано на рисунке.

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

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

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

    Свойство 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 контроллере ( смотри нижеследующий код ).

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

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

    Dr.Gigabit Гость

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

    Pasha Гость

    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.
     
  4. Dr.Gigabit

    Dr.Gigabit Гость

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

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

    karlito Гость

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

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

    Для: Dr.Gigabit
    убИвать... ХА-ха-ХА...

    Ничо не понял. обработчики всё равно остаются клиентские, JavaStript-овые.

    Для: Pasha
    Поддерживаю.

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

    Pasha Гость

    <!--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".
     
  7. Pasha

    Pasha Гость

    Для: NikSoft
    пример (не очень аккуратный, нарисован только для демонстрации)
    Код (Text):
    <%@ 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>
    Код (Text):
    // 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);
    }
    }
    }
     
Загрузка...

Поделиться этой страницей