Easy ways to wire up foreign events to a DataGrid
Download C# Sample Code
Introduction and Overview
DataGrids seem to be very popular among all ASP.NET developers these days.
I've seen whole series of articles and a lot powerful custom controls released
for it. I personally think they are great as long as you manage your Viewstate
size and don't try to think too much outside the box, or grid in this case.
Anyhow, one thing that has bothered me is that it isn't easy to wire up events
like, OnSelectedItemIndexChange, in template columns containing controls like
the RadioButtonList or DropDownList. They just don't seem to play well with
the DataGrid like the LinkButton or ImageButton.
If you are using VS.NET and try to view events of a RadioButtonList control,
you'll notice that the lighting bolt is no where insight. That implyed to me
that you couldn't wire up any events to that object. One of my partners pointed
out to me that it would be impossible for the IDE to wire up the event in the
CS, because that object is created until the DataGrid crated on the page. With
that in mind we both decided that we should just be able to intercept on the
OnItemDataBound and wire up the event right there and we would be all set. Much
to his and my surprise the event never fired, and all the news groups just said
"make sure autopostback is enabled", well.. duh! Anyhow my partner came up with
a quick fix by adding some javascript to the drop-down list that fired the onClick
on a LinkButton that had no text which was rendered as an empty href. Ugly,
but it worked.
I dug a little deeper and moved our intercept code to the OnItemCreate event
of the DataGrid. Like magic everything started working, why it doesn't work
in the DataBind still puzzles me. I thought back to early PDC bits of ASP.NET
when there was no VS.NET and remembered wiring my events right in the tag itself.
I guess I've gotten lazy with VS.NET and letting it register all my events progamatically.
I wired the event on the ASPX side and changed its accessibility from private
to protected and the event on the DropDownList fired without having to implent
it on the DataGrid onItemCreate. The only problem we had now was how to figure out which row the event came from on the DataGrid.
How do I find out which row on the DataGrid the event was fired from?
All DataGrid Command Events use the DataGridCommandEventArgs which has a nice reference to the command source of the event. A lot of useful information can be found there such as ItemIndex and the DataItem.
Events like OnSelectedIndexChanged found in controls like the RadioButtonList and CheckBoxList can't be wired into the ItemCommand event of the Datagrid. This presents a problem
when trying to get to the row of the Control that just kicked off an event. I've solved this problem two ways, one home grown method and another method that takes advantage of the control heichary of ASP.NET.
Heirchary Method
Using the .Parent of a control returns its containing control. Each control in a templated column in a DataGrid
lives in a TableCell which lives in a DataGridItem. So the quickest way to get to the DataGridItem is to just do a .Parent.Parent
and cast the object into a DataGridItem and you'll have all the same information that is contained in the DataGridCommandEventArgs.Item. Things can
get tricky if you have another container control like a Panel, but you should always be able to walk up the tree to get to the DataGridItem.
Helper Function Method
I'm not a big fan of this method even though I wrote it, but it will return the DataGridItem as well. Each Control on a ASP.NET
page has a property called ClientID. There is a very logical naming pattern for controls within a DataGrid and this method just parses the ClientID
and returns the DataGridItem based on the index of the ClientID. Not pretty, but it works. Just cut and paste and pass in the controls ClientID and
the DataGrid the control is located on.
private DataGridItem GetDataGridItem(string pClientID, DataGrid pDataGrid)
{
string myRowID = pClientID;
myRowID = myRowID.Substring(myRowID.IndexOf("__ctl")+5);
myRowID = myRowID.Substring(0,myRowID.IndexOf("_"));
if (pDataGrid.ShowHeader)
return pDataGrid.Items[int.Parse(myRowID)-2];
else
return pDataGrid.Items[int.Parse(myRowID)-1];
}
|
A DataGrid can only have one "Edit Item" at a time, so how often would I have more than one drop-down list?
Some people are stuck in the mode of only editing one item at a time in a DataGrid. That can be come painfully slow for some interfaces and force
the user to constantly click Edit & Update buttons over and over. It is perfectly legal and logical to put a drop-down list or RadioButtonList in the ItemTemplate portion of a
Template Column. The Sample application included with this How-To has three DataGrids with three seperate shopping lists. Items within each shopping list can be
moved to any other list. This interface quickly allows items to be moved between the three grids without having to click edit and update over and over.
The sample application shows all the ways I talked about above in how to implement Foreign Event capturing on a DataGrid. One method registers the event on the ASPX side, the second
registers the event on the OnItemCreate and the third creates the control and adds the event all in the OnItemCreate.
A Screen Shot of the Sample Application

Final Thoughts
I'm still not quite sure why Microsoft hides the events icon, you would think the IDE would have the smarts to place the event in the tag or
the codebehind. Also, I'm not quite clear why you can't wire the event on the onItemDataBound.
Something to remember about DataGrids is that they are very ViewState heavy. Most people find out when they disable ViewState on an DataGrid most of their functionality goes away, like
paging. The best way to control ViewState size is to convert all your bound columns to template columns and disable ViewState on your Labels.
Another thing that takes up ViewState are the Edit, Update, Delete & Cancel Buttons. Convert those columns and disable ViewState on those buttons,
you don't need ViewState on those buttons to make them work, unless you do some mods to them on your codebehind! Good Luck and Happy Coding!