ASP.NET GridView – OnRowDataBound vs OnRowCreated

This morning, while I was creating a simple ASP.NET page, I have 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 fully charged 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:

gridTest1_GridView1_ctl02_txtSelectedValue

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

<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 in detail the code:

<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:

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:

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:

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:

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:

<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 in detail this behavior, but as we know … time is short and the important thing is … … everyone lived happily ever!!


CodeProject

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s