Accessing the a Particular Row's TemplateColumn's Contents
By: Scott Mitchell | Created: 2003-07-10 | Last Updated: 2003-07-10



There are often times with the DataGrid when you will need to access the value in a particular column of a particular row. One of the most common examples of this is when using the DataGrid to edit database data. In this scenario, after the user makes a row editable, edits the values, and then clicks the Update button, you need to programmatically determine the updated values and perform a database update.

The two DataGridColumn types you're likely to need to access values from are the BoundColumn and the TemplateColumn. This FAQ focuses on programmatically accessing the value from a particular TemplateColumn in a particular DataGrid row. To see how to access the values from a BoundColumn, be sure to read the Accessing BoundColumn Contents FAQ. This other FAQ also contains a good discussion on DataGrids and DataGridItems, and should be read prior to reading this FAQ.

DataLists and Repeaters...
Since DataLists and Repeaters use templates, the discussion in this FAQ is also applicable for retrieving the value from a template in a DataList or Repeater.

The Contents of a TemplateColumn
Compared to the BoundColumn, TemplateColumns allow for a tremendous amount of customization. The BoundColumn, as you likely know, simply displays the value of a DataSource field. While you can customize the font, color, and horizontal spacing, among other things, the BoundColumn can still be described as only be able to do one thing: display the textual content from a particular DataSource field.

The TemplateColumn, on the other hand, allows you to specify a mixture of HTML syntax and Web controls. This mixed content then appears in the column. For example, in another FAQ, Combining Two DataSource Fields Into One DataGrid Column, we saw how to use a TemplateColumn and some databinding syntax to display two DataSource fields in one DataGrid column.

TemplateColumns are often the choice du jour when creating an editable DataGrid because they allow for much more flexibility in the editing interface as well. Specifically, the TemplateColumn contains an EditItemTemplate, which is the template that is used when the editable row is being rendered. For example, if you wanted to display the editable interface for a column as a small TextBox Web control with an associated RequiredFieldValidator control, you would have to use a TemplateColumn as opposed to a BoundColumn. The TemplateColumn's editing interface could be defined thusly:

<asp:DataGrid ...> <Columns> ... <asp:TemplateColumn> <ItemTemplate> <b><%# DataBinder.Eval(Container.DataItem, "SSN") %></b> </ItemTemplate> <EditItemTemplate> <asp:TextBox runat="server" id="txtSSN" Columns="9" Text='<%# DataBinder.Eval(Container.DataItem, "SSN") %>' /> <asp:RequiredFieldValidator runat="server" Display="Dynamic" ControlToValidate="txtSSN" ErrorMessage="You must provide a SSN value." /> </EditItemTemplate> </asp:TemplateColumn> </Columns> </asp:DataGrid>

In the above example, the row currently being edited will display a TextBox Web control with nine columns. A RequiredFieldValidator is in place to ensure that the user supplies a value. All other rows will display the SSN field in a bold font.

Now, the challenge lies in programmatically accessing the vlaue of the txtSSN TextBox Web control when the user clicks the Update button. Recall that to access the BoundColumn's TextBox's value, we used the following syntax within the UpdateCommand event handler:

Dim myTextBox = CType(e.Item.Cells(index).Controls(0), TextBox) Dim textBoxValue as String = myTextBox.Text
VB.NET

 

TextBox myTextBox = (TextBox) e.Item.Cells(index).Controls(0); string textBoxValue = myTextBox.Text;
C#

 

This works because when the BoundColumn is displayed in its editable mode, a single TextBox control is added as the Cells(index) object's sole control. With the TemplateColumn, however, a bevy of controls might be added. Where can all these controls come from? First off, a TemplateColumn can have multiple Web controls specified within it. In our earlier example, we had two such Web controls: a TextBox and a RequiredFieldValidator. Furthermore, realize that all HTML markup between Web controls in the TemplateColumn are rendered as LiteralControls (including whitespace). For example, assume our TempalteColumn looked like so:

<asp:TemplateColumn> <ItemTemplate> ... </ItemTemplate> <EditItemTemplate> SSN: <asp:TextBox runat="server" id="txtSSN" Columns="9" Text='<%# DataBinder.Eval(Container.DataItem, "SSN") %>' /> <asp:RequiredFieldValidator runat="server" Display="Dynamic" ControlToValidate="txtSSN" ErrorMessage="You must provide a SSN value." /> </EditItemTemplate> </asp:TemplateColumn>

Now, the EditItemTemplate contains two Web controls and some HTML markup. The HTML markup is SSN: , right before the TextBox Web control, and then the carraige return and spacing after the TextBox but before the RequiredFieldValidator. This means our TemplateColumn will generate four controls: a LiteralControl containing SSN: , a TextBox Web control, a LiteralControl containing a carraige return and some whitespace, and a RequiredFieldValidator Web control. That means, if we used syntax like with the BoundColumn, e.Item.Cells(index).Controls(0), we would get the first control in the Controls collection, which would be a LiteralControl containing the content SSN: . In order to access the proper TextBox we'd have to use e.Item.Cells(index).Controls(1). Of course, the precise index could change if we edited the EditItemTemplate at a later date, which would lead to errors, which would lead to a big ol' headache.

So, each TemplateColumn will have several controls, only one of which is the TextBox Web control we're interested in. What we need to do to avoid having to enter a hard-coded number as a refernce to the Controls collection, is to set the ID property of the Web control we're interested in. In the DataGrid declaration above, we set the SSN TextBox's ID to txtSSN. Then, programmatically, we can access this TextBox using the FindControl() method like so:

Sub myDataGrid_Update(sender as Object, e as DataGridCommandEventArgs) 'Read in the value from the TemplateColumn's SSN TextBox Dim ssnTextBox as TextBox = CType(e.Item.Cells(1).FindControl("txtSSN"), TextBox) Dim ssnValue as String = ssnTextBox.Text ... Update the database ... ... Reset EditItemIndex to -1 and Rebind the DataGrid ... End Sub
VB.NET

 

void myDataGrid_Update(Object sender, DataGridCommandEventArgs e) { // Read in the values from the BoundColumn TextBoxes TextBox ssnTextBox = (TextBox) e.Item.Cells[1].FindControl("txtSSN"); string ssnValue = ssnTextBox.Text; ... Update the database ... ... Reset EditItemIndex to -1 and Rebind the DataGrid ... }
C#

 

That's all there is to it! Here, we are assuming that the TemplateColumn is the second column in the DataGrid (hence the Cells(1)).

Programmatically Accessing Controls in a BoundColumn
To learn how to programmatically access the Web controls in a BoundColumn be sure to read the Accessing BoundColumn Contents FAQ!


Home | FAQs | Articles | About | Buy the Book!

Copyright 2006, Scott Mitchell. All Rights Reserved.