protected void LinkButton1_Click(object sender, EventArgs e)
{
LinkButton lb = (LinkButton)sender;
int orderID = int.Parse(lb.Attributes["OrderID"]);
// ...
}
It's quick, it works and while it doesn't seem like the "Microsoft approved" method to me, it is more scalable than the counting the cells (If your OrderID is rendered as a label in the third column, you might use Convert.ToInt32(row.Cells(2).Text); to obtain the orderid). But what happens when you or someone else adds an additional column to the gridview in front of orderid? Suddenly your orderid might be something else entirely and if it still compiles and runs perhaps no one will even notice!
Let's explore two more quick examples that adhere to what Microsoft had in mind. The first, again assumes you add OnClick="LinkButton_Click" to your linkbutton inside the gridview and that you need not only the orderid, but also the Primary Key and the value of TextBox1:
protected void LinkButton1_Click(object sender, EventArgs e)
{
LinkButton lb = (LinkButton)sender;
GridViewRow row = (GridViewRow)lb.NamingContainer;
// get the value of the textbox
TextBox txt1 = row.Cells[4].FindControl("TextBox1") as TextBox;
string phoneNumber = txt1.Text;
// get the Primary Key Value
int ID = GridView1.DataKeys[row.RowIndex].Value;
// ... Do something with these values like update a row in a database
}
It is unfortunate that you cannot address a cell by anything other than its Index as if you later need to add another column in front of this one, your application will break. You might think this is no big deal, but consider what happens if you have this sort of code applied to two or three columns, and each one addresses multiple cells.
Then your boss asks you to add a new column. Trust me, you will groan, as you now have to recalculate the index of all cells addressed in this fashion. It can turn a 2 minute task into a 20 minute task.
As an alternative to the OnClick Event applied to an individual button, you can instead use the RowCommand Event of the GridView. This allows you to store some data inside the ComandArgument property of your button, which is arguably similar to the custom attribute method discussed at the beginning of this article, but since you can only set one command argument, if you need three pieces of information from it you are faced with a choice of either combining the information through concatenation - setting your command argument up as a string you plan to split apart later e.g. "OrderID=123|ProductID=456" or you are back to counting cells. And what's more, despite what this MSDN article implies, the CommandArgument does NOT contain the RowIndex by default, you would need to add it there yourself which can be done declaratively like so:
<asp:LinkButton ID="LinkButton1" runat="server"CommandArgument='<%# gv.Rows.Count.ToString() %>' CommandName="UpdatePhone">Get Row Info</asp:LinkButton>
Then your RowCommand Handler would look something like this:
protected void GridView1_RowCommand(Object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "UpdatePhone")
{
// Convert the row index stored in the CommandArgument
// property to an Integer.
int index = Convert.ToInt32(e.CommandArgument);
// Retrieve the row that contains the button clicked
// by the user from the Rows collection.
GridViewRow row = GridView1.Rows[index];
// get the value of the textbox
TextBox txt1 = row.Cells[4].FindControl("TextBox1") as TextBox;
string phoneNumber = txt1.Text;
// get the Primary Key Value
int ID = GridView1.DataKeys[row.RowIndex].Value;
// ... Do something with these values like update a row in a database
}
}
Conclusions
So there you have it. Three ways to Handle the onClick event of a button in a grid view. In my opinion, the OnRowCommand Event of the GridView is the least useful of them when trying to fulfil this brief. Sure it gives you the CommandArgument property, but you immediately need to use it for storing the row index. Whenever possible, I usually choose a Microsft approved approach so this time I opted for the OnClick event of the button but if I have to come back and add another column again, I'll probably use the custom attributes approach, because I do not want to have to increment/decrement all the cell index values again.