This post originated from an RSS feed registered with .NET Buzz
by Scott Hanselman.
Original Post: Bringing data "along for the ride" with CheckBoxes and the ASP.NET DataGrid
Feed Title: Scott Hanselman's ComputerZen.com
Feed URL: http://radio-weblogs.com/0106747/rss.xml
Feed Description: Scott Hanselman's ComputerZen.com is a .NET/WebServices/XML Weblog. I offer details of obscurities (internals of ASP.NET, WebServices, XML, etc) and best practices from real world scenarios.
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:
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).
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.