Scott Hanselman

Bringing data "along for the ride" with CheckBoxes and the ASP.NET DataGrid

December 04, 2003 Comment on this post [5] Posted in ASP.NET | XML
Sponsored By

Recently I needed to have a DataGrid that had multiple checkboxes to activate and deactivate something.  So, you could check a whole slew of checkboxes in a big grid, and depending on the NEW state of the checkbox (checked or not), cause an operation on a theorectical back end.

Here's some opinion/thought/zen on the DataGrid, and DataGridGirl will have to tell you if I'm wrong or not.

  • Work WITH the Grid, not against it: If you find yourself filling up the Grid via DataBinding, THEN running around in the rendered grid with foreach this and foreach that looking for HTML controls, you probably want to rethink things.  Look to the Events, my son.
  • Listen to the Events and Nudge/Influence the Grid: Between OnItemCreated and OnItemDataBound, you've got some serious influence on the grid.  If you can't get things to happen declaratively in the ItemTemplate, get them to happen Programmatically in these events.
  • Avoid Hidden Columns with IDs of things: In my case, I needed to hear when a checkbox's state changed, and at that time, I needed to know the ProductID associated with that checkbox.  Rather than wadnering around in the Control Tree (ala DataItem[x].Parent.Parent.Parent, etc.FindControl("yousuck"), just bring the data along for the ride.  See my solution below.
  • Just because code is on CodeProject or in Google Groups doesn't mean the writer knows the DataGrid from his Ass:  <rant>If I see one more solution in CodeProject or Google where someone says, "ya, just (DataTime)(((TextBox)Whatever.Item.Parent.Parent.Child[0].Parent.BrotherInLaw).Text).IntValue.ParseExact('yyyy/mm/dd')) and you're there" I will seriously hurt someone.  The DataGrid has it's faults, sure, but it's a lot more subtle that .DataBind and brute force it.  This some problem has happened with the XML DOM, and it's all the fault of QuickWatch.  "Gosh, I can SEE the data, so it must be OK for me to spelunk for it."  </rant>

I needed to know when the checkbox changed, then act on it.  So I remembered the order of events during a postback (and you should too):

  • Events fire in control tree order
  • THEN the control that CAUSED the PostBack fires it's event LAST.

So, I'd get a bunch of CheckBox_Changed events, and finally a Button_Click (from an 'Update' button).

In the Changed events I loaded a page-scoped ArrayList of things to act on, like, ProductIdsToActivateArrayList or ProductIdsToDeleteArrayList, depending on how many columns in my grid had checkboxes.  As the Changed events fire, I just wanted to load up the ProductIDs for that CheckBox's row.  But, how to avoid running around in the control tree? (which is, as I said before, gross)

I needed the data to come 'along for the ride' with the CheckBox_Changed Events.  So in the .ASPX page:

<ItemTemplate><asp:CheckBox id='checkbox' ProductId='<%#DataBinder.Eval(Container.DataItem, "ProductID")%> OnChecked='CheckBoxChanged'>

Notice that!  A totally random and unknown attribute in the CheckBox's statement.  Is that allowed? How will it render?  Well, it is allowed (although VS.NET's Designer will complain).

It renders, interestingly enough, like this:

<span ProductId="4"><input type="checkbox" id="checkbox" name="checkbox"></span>

Look at the extra span!  Crazay.  Then in the CheckBoxChanged event on the server-side after someone clicks a bunch of CheckBoxes and clicks Update:

public void CheckBoxChanged(object sender, EventArgs e)
{
     string ProductID = ((CheckBox)sender).Attributes["ProductID"]).ToString();
     ProductsToDeleteArrayList.Add(ProductID);
}

Then in the Button_Click event (remember, that happens AFTER all this) I spin through the ArrayLists (there are several, one for each action) and perform the actions in a batch.  This makes the Button_Click code CLEAN.  It makes the CheckBoxChanged code CLEAN, and it bypasses a whole lot of running around in the control tree.

Also, before I forget: Congratulations to Robert for the birth of the definitive Scrolling Data Grid.  Kudos.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
December 05, 2003 2:06
Cool, I never thought to just add the attribute in the item template. Whenever I needed to do such things I usually added the attribute in the itemDataBound event. Also in most cases I've been able to get away with setting the DataKeyField of the data grid to my identity property (ProductID) and then accessing it through myGrid.DataKeys[e.Item.ItemIndex].
December 05, 2003 5:07
Great stuff, Scott. I have been doing a lot of work with the datagrid recently and come across some of the same things. Just recently we migrated away from using a datagrid where you always had to set the EditItemIndex and update one row at a time, to using a datagrid where you load up textboxes, checkboxes, and whatever else in the ItemTemplate and don't force the thing to only update one row at a time. Unfortunately for us, we didn't do this until we spent some time trying to create our own custom dynamic html table. Modeless datagrid! Egads!
July 30, 2004 18:45
This datagrid tip just saved me. Thank you!!
August 23, 2005 20:08
Whathappened to "Robert's definitve Scrolling DataGrid"? It is just a search page now?
October 06, 2005 15:36
This is really cool code. But do u have a reverse code of this -- i mean, get the ID when the user 'UNCHECK' the checkbox. When my page load, the checkboxes on the grid are already checked. The user then, unchecks any record, then click the submit button to update those records that were unchecked.

Thanks!

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.