SYSK 331: How To Expose A Client-Side Event From Your ASP.NET Control

Consider the following scenario – you create your own calendar control and you’d like to raise an event when a date is selected (e.g. OnDateClicked)… and you’d like for the users of your calendar control to process the event using JavaScript on the client (or think of any other scenario of when a custom client-side event would be useful).

There are plenty samples on how to fire a server-side event, but none that I can find on how to raise one on the client. The code below shows how to make it happen…

1. Implement System.Web.UI.IScriptControl interface

using System;

using System.Data;

using System.Configuration;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Web.UI.HtmlControls;

[assembly: System.Web.UI.WebResource("MyTableCtrl.Scripts.MyTable.js", "text/javascript")]

namespace MyControls

{

    public class MyTable : System.Web.UI.HtmlControls.HtmlTable, System.Web.UI.IScriptControl

    {

        private string _cellClickedDelegate;

        public MyTable()

        {

            base.Border = 1;

            for (int i = 0; i < 5; i++)

            {

                HtmlTableRow tr = new HtmlTableRow();

                for (int j = 0; j < 3; j++)

                {

                    HtmlTableCell td = new HtmlTableCell();

                    td.InnerHtml = string.Format("&nbsp;{0}.{1}&nbsp;", i + 1, j + 1);

                    td.Style["cursor"] = "hand";

                    tr.Cells.Add(td);

                }

                base.Rows.Add(tr);

            }

        }

        protected override void OnPreRender(EventArgs e)

        {

            if (this.DesignMode == false)

      {

                ScriptManager sm = ScriptManager.GetCurrent(this.Page);

                if (sm != null)

                    sm.RegisterScriptControl(this);

            }

            base.OnPreRender(e);

        }

        protected override void Render(HtmlTextWriter writer)

        {

            if (this.DesignMode == false)

            {

                ScriptManager sm = ScriptManager.GetCurrent(this.Page);

                if (sm != null)

                    sm.RegisterScriptDescriptors(this);

  }

            base.Render(writer);

        }

       

        #region IScriptControl Members

        // Expose client side property for the cellClicked event

        public string cellClicked

        {

            get { return _cellClickedDelegate; }

            set { _cellClickedDelegate = value; }

        }

        public System.Collections.Generic.IEnumerable<ScriptDescriptor> GetScriptDescriptors()

        {

            System.Collections.Generic.IEnumerable<ScriptDescriptor> result = null;

            if (string.IsNullOrEmpty(_cellClickedDelegate))

            {

                result = new ScriptDescriptor[] { };

            }

            else

            {

                ScriptControlDescriptor descriptor = new ScriptControlDescriptor(this.GetType().FullName, this.ClientID);

                descriptor.AddEvent("cellClicked", _cellClickedDelegate);

                result = new ScriptDescriptor[] { descriptor };

            }

            return result;

        }

        public System.Collections.Generic.IEnumerable<ScriptReference> GetScriptReferences()

        {

            return new ScriptReference[] { new ScriptReference("MyTableCtrl.Scripts.MyTable.js", System.Reflection.Assembly.GetAssembly(this.GetType()).FullName) };

        }

        #endregion

    }

}

2. Implement event subscription and firing in a JavaScript file (e.g. Scripts\MyTable.js)

 

Type.registerNamespace("MyControls");

MyControls.MyTable = function(element)

{

    MyControls.MyTable.initializeBase(this, [element]);

}

MyControls.MyTable.prototype =

{

    initialize: function()

    {

        MyControls.MyTable.callBaseMethod(this, 'initialize');

       

        $addHandlers(this.get_element(), { 'click':this._onCellClicked }, this);

    },

    add_cellClicked : function(handler)

    {

        this.get_events().addHandler("cellClicked", handler);

    },

    remove_cellClicked : function(handler)

    {

        this.get_events().removeHandler("cellClicked", handler);

    },

    _onCellClicked: function(source, e)

    {

        if (!this._events) return;

        var handler = this._events.getHandler("cellClicked");

        if (handler)

            handler(source.rawEvent.srcElement);

    },

    dispose: function()

    {

        $clearHandlers(this.get_element());

        MyControls.MyTable.callBaseMethod(this, 'dispose');

    }

}

MyControls.MyTable.registerClass("MyControls.MyTable", Sys.UI.Control);

 

 

3. Subscribe for the event

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<% @ Register Assembly="System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

    Namespace="System.Web.UI" TagPrefix="asp" %>

<% @ Register Assembly="MyTableCtrl" Namespace="MyControls" TagPrefix="cc" %>

<!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>Untitled Page</title>

</head>

<body>   

    <form id="form1" runat="server">

        <asp:ScriptManager ID="ScriptManager1" runat="server" >

        </asp:ScriptManager>

        <cc:MyTable runat="server" id="table1" cellClicked="OnCellClicked"></cc:MyTable>

    </form>

   

    <script type="text/javascript">

        function OnCellClicked(cell)

        {

            alert("OnCellClicked: " + cell.innerText);

        }

    </script>

</body>

</html>