Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / ASP.NET

ASP.NET GridView – OnRowDataBound vs OnRowCreated

4.25/5 (4 votes)
27 Aug 2012CPOL2 min read 33K  
How to manage JavaScript and events for GridView

This morning, while I was creating a simple ASP.NET page, I fought a couple of hours versus a GridView that apparently worked in strange ways.

Problem Description

The problem I encountered seemed to be the wrong setting of the property “ID” of the client-side controls. Generally, the ASP.NET engine (prior to version 4.0) takes full charge to change the ID to avoid duplication, so that they are always unique. Particularly in the case of a GridView fact, for a control that we insert with ID = “txtSelectedValue”, and that is repeated for each row of the grid, will have a ClientID like this:

C#
gridTest1_GridView1_ctl02_txtSelectedValue

This morning, I spent some time to figure out why the control was instead generated in this way:

XML
<input id="txtSelectedValue" type="text" name="txtSelectedValue" />

Code Description

The GridView included a column with a ComboBox which was to run a JavaScript function to select a value. To better understand, we immediately see the code in detail:

XML
<Columns>
    <asp:TemplateField>
        <ItemTemplate>
            <asp:TextBox runat="server" ID="txtSelectedValue" Text="" />
        </ItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField>
        <ItemTemplate>
            <asp:DropDownList runat="server" ID="ddlChoice">
                <asp:ListItem Text="--" />
                <asp:ListItem Text="text1" />
                <asp:ListItem Text="text2" />
                <asp:ListItem Text="text3" />
                <asp:ListItem Text="text4" />
            </asp:DropDownList>
        </ItemTemplate>
    </asp:TemplateField>
</Columns>

and this is the JavaScript function:

JavaScript
function selectChoice(ddl, textboxID) {
    var chosenoption = ddl.options[ddl.selectedIndex];
    if (chosenoption.value != 'nothing') {
        document.getElementById(textboxID).value = chosenoption.value;
    }
}

Wanting to add the JavaScript function to DropDownList programmatically, I chose to act on the OnRowCreated grid event like this:

C#
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        DropDownList ddlChoice = e.Row.FindControl("ddlChoice") as DropDownList;
        TextBox txtSelectedValue = e.Row.FindControl("txtSelectedValue") as TextBox;

        string jScript = "selectChoice(this, '{0}');";
        ddlChoice.Attributes.Add("onchange", string.Format(jScript, txtSelectedValue.ClientID));
    }
}

The example shown here may have little practical significance, but in the daily demands we may be in a similar situation.

As you can see from the code, changing the value of the ComboBox, we act on the client side via the onchange event of <select> control to copy the value into another HTML control, and in this way you avoid unnecessary PostBack of the ASPX page, and avoid requests and execution of the code by the ASP.NET engine.

Having a set of controls all with the same id, of course the JavaScript function returns an error to the following line:

JavaScript
document.getElementById(textboxID).value = chosenoption.value;

because the getElementById method returns the first HTML control with the specified id, thereby defeating the entire utility function. And here’s the wrong line:

C#
ddlChoice.Attributes.Add("onchange", string.Format(jScript, txtSelectedValue.ClientID));

Probably, I think of that, the ASP.NET engine at this point did not create unique IDs, and with reference to the control’s ClientID property, probably, I again thought, the ASP.NET engine decides to keep the static ID. In fact, merely commenting on the line above, all work normally.

Solution

So how to send the TextBox control’s ID to the JavaScript function?

Referring to my few neurons still working, I seemed to remember that the RowCreated event is raised before RowDataBound, so I figured that postponing the use of the ClientID property, I might have solved the problem.

In doing so, it was enough to move the code written in OnRowCreated delegate in OnRowDataBound delegate, to get the desired result. Here is the code generated in this case:

XML
<tr>
    <td>
        <input name="gridTest1$GridView1$ctl03$txtSelectedValue" 
           type="text" id="gridTest1_GridView1_ctl03_txtSelectedValue" />
    </td>
    <td>
        <select name="gridTest1$GridView1$ctl03$ddlChoice" 
                  id="gridTest1_GridView1_ctl03_ddlChoice" 
                  onchange="selectChoice(this, 'gridTest1_GridView1_ctl03_txtSelectedValue');">
            <option value="--">--</option>
            <option value="text1">text1</option>
            <option value="text2">text2</option>
            <option value="text3">text3</option>
            <option value="text4">text4</option>
        </select>
    </td>
</tr>

Conclusion

I do not have in-depth studies to understand this behavior in detail, but as we know … time is short and the important thing is … … everyone lived happily ever!!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)