views:

414

answers:

1

I am looking for a way to programmatically set the OnClick event handler for a TableCell object. The ASP equivalent of what I'm trying to do will look like this:

<asp:TableCell OnClick="clickHandler" runat="server">Click Me!</asp:TableCell>

In the above example, "clickHandler" is a server-side function defined in the .cs CodeBehind.

public virtual void clickHandler(object sender, EventArgs args) {...}

However, for my situation, this TableCell object needs to be created dynamically, so setting it in an ASP tag is not an option. I am trying to do something like the following in the CodeBehind:

System.Web.UI.WebControls.TableRow row = new System.Web.UI.WebControls.TableRow();
System.Web.UI.WebControls.TableCell cell = new System.Web.UI.WebControls.TableCell();
cell.Text = "Click Me!";
cell.Attributes.Add("onClick", "clickHandler");
row.Cells.Add(cell);

Unfortunately, in this situation:

cell.Attributes.Add("onClick", "clickHandler");

the "clickHandler" only works as a client-side javascript function. What I'm looking for is a way to link the server-side clickHandler() function, defined in the .cs CodeBehind, to this table cell.

After an afternoon of searching, I have been unable to come up with a working solution. Thanks in advance for any help.

+1  A: 

After a lot of work and research, I was able to cobble together a working solution, but it seems like an awful lot of work for something that should already be built-in. What I did was to extend the System.Web.UI.WebControls.TableCell object to include a handle for the OnClick event:

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

namespace MyWebApp
{


    public class ExpandableTableCell : TableCell, IPostBackEventHandler, INamingContainer
    {
        private static readonly object click_event = new object();

        public ExpandableTableCell()
        {
        }

        // public handles for adding and removing functions to be called on the click event
        public event EventHandler Click
        {
            add
            {
                Events.AddHandler(click_event, value);
            }
            remove
            {
                Events.RemoveHandler(click_event, value);
            }
        }

        // define parent function that will be called when the container is clicked
        protected void Click(EventArgs e)
        {
            EventHandler h = Events[click_event] as EventHandler;
            if (h != null)
            {
                h(this, e);
            }
        }

        // specify the "post back event reference" or id of the click event
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            base.AddAttributesToRender(writer);
            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, 
                                Page.ClientScript.GetPostBackEventReference(this, "custom_click"));
        }

        // link the custom click id to the click function
        void System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
        {
            if(eventArgument == "custom_click")
            {
                this.OnClick(EventArgs.Empty);
            }
        }
    }
}

Here is how I use my new class (almost exactly like the stock TableCell):

System.Web.UI.WebControls.TableRow row = new System.Web.UI.WebControls.TableRow();
ExpandableTableCell click_cell = new ExpandableTableCell();
click_cell.Text = "Click Me!";
click_cell.Click += clickHandler;
// extra little touch for mouseover event
click_cell.Attributes.Add("onmouseover", "this.style.cursor='pointer'");
row.Cells.Add(click_cell);

As I have said, it seems like going through the trouble of extending the class to set the OnClick method in the codebehind is excessive. If anyone has any other ideas or any ways to clean up or legitimize the code above, please let me know.

Corey O.