This stemmed from a question on a mailing list and I had most of the answer, but have now discovered something that's now new, but is new to me.
When using a GridView you often have command buttons that perform some command on the row. Not the selected row, because selection is something different. generally I do this by giving my buttons a CommandName and handling the RowCommand event of the grid. The problem has been how do I get the row number and also the key value for that item in the row.
If you use a ButtonField this is easy, because the ButtonField automatically sets its CommandArgument property to the row number; when you think about it, you can set the CommandName of the ButtonField, but not the CommandArgument; why not? Because it's set for you. Yeah, who knew? In the RowCommand event you can then just extract this with:
int rowNum = int.Parse(e.CommandArgument.ToString());
If you're using a templated field, there are two ways. The first is to set the CommandArgument yourself. For example:
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="IncreasePriceButton" runat="server"
Text="+10%"
CommandName="IncreasePrice"
CommandArgument='<%# Container.DataItemIndex %>' />
<asp:Button ID="DecreasePriceButton" runat="server"
Text="-10%"
CommandName="DecreasePrice"
CommandArgument='<%# Container.DataItemIndex %>' />
</ItemTemplate>
</asp:TemplateField>
Here DataItemIndex represents the row number. Within the RowCommand you can extract this in the same way, just getting the value from e.CommandArgument. If you can't use CommandArgument, perhaps becuase you need it for passing in other types of data, then you can still get the row number, but have to do a bit more work:
int rowNum = -1;
GridViewRow row = ((e.CommandSource as Control).NamingContainer as GridViewRow);
if (row != null)
{
rowNum = row.RowIndex;
}
It's not quite as elegant, but works just as well.