Abstract
在.NET 1.x的DataGrid,可以在ItemCommand event的e.Item.ItemIndex獲得目前的RowIndex,但在.NET 2.0的GridView,卻無法使用這種方式在RowCommand event獲得RowIndex。
Motivation
為什麼需要在RowCommand event獲得RowIndex呢?通常一個Table的PK或FK並不會顯示在GridView上,而會設定在DataKeyNames property,然後再RowCommand event根據RowIndex讀出該row的PK或FK,所以第一步,必須先能在RowCommand獲得目前的RowIndex。
Introduction
.NET 1.x DataGrid
在.NET 1.x的DataGrid,若要使用LinkButton,一樣得放在TemplateColumn內,且ItemCommand event的e.Item.ItemIndex就可抓到RowIndex。
當在DataGrid點下FirstName後,會在下方的Label顯示LastName,LastName是此例的DataKey。
<%@ Import Namespace="System.Data" %>2
<%@ Import Namespace="System.Data.SqlClient" %>3

4
<%@ Page Language="C#" %>5

6
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">7

8
<script runat="server">9
/* 10
(C) OOMusou 2007 http://oomusou.cnblogs.com11

12
Filename : DataGrid_DataKeyField.aspx13
Compiler : Visual Studio 2005 / C# 2.0 / ASP.NET 2.014
Description : Demo how to get RowIndex in DataGrid's LinkButton15
Release : 06/26/2007 1.016
*/17
protected void Page_Load(object sender, EventArgs e) {18
if (!IsPostBack) 19
DataGrid1_DataBind();20
}21

22
protected void DataGrid1_DataBind() {23
string strSQL = "SELECT TOP 10 " +24
"fname," +25
"lname " +26
"FROM employee";27
SqlConnection con = new SqlConnection(@"Data Source=.\sqlexpress;Initial Catalog=pubs;Integrated Security=True");28
SqlDataAdapter da = new SqlDataAdapter(strSQL, con);29
DataSet ds = new DataSet();30

31
try {32
da.Fill(ds);33
}34
catch (Exception err) {35
Response.Write(err.ToString());36
return;37
}38
finally {39
if ((con != null) && (con.State == ConnectionState.Open))40
con.Close();41
}42

43
DataGrid1.DataSource = ds;44
DataGrid1.DataKeyField = "lname";45
DataGrid1.AutoGenerateColumns = false;46
DataGrid1.DataBind();47
}48

49
protected void DataGrid1_ItemCommand(object source, DataGridCommandEventArgs e) {50
if (e.CommandName == "Select")51
Label1.Text = DataGrid1.DataKeys[e.Item.ItemIndex].ToString();52
}53
</script>54

55
<html xmlns="http://www.w3.org/1999/xhtml">56
<head runat="server">57
<title>Untitled Page</title>58
</head>59
<body>60
<form id="form1" runat="server">61
<asp:DataGrid ID="DataGrid1" runat="server" OnItemCommand="DataGrid1_ItemCommand">62
<Columns>63
<asp:TemplateColumn HeaderText="First Name">64
<ItemTemplate>65
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="Select" Text='<%#DataBinder.Eval(Container.DataItem,"fname")%>'>66
</asp:LinkButton>67
</ItemTemplate>68
</asp:TemplateColumn>69
</Columns>70
</asp:DataGrid>71
<asp:Label ID="Label1" runat="server"></asp:Label>72
</form>73
</body>74
</html>
51行
protected void DataGrid1_ItemCommand(object source, DataGridCommandEventArgs e) {2
if (e.CommandName == "Select")3
Label1.Text = DataGrid1.DataKeys[e.Item.ItemIndex].ToString();4
}5

只需在ItemCommand event的e.Item.ItemIndex就可以輕鬆的抓到RowIndex。
.NET 2.0 GridView
.NET 2.0就改用SqlDataSource和GridView了,LinkButtom一樣得放在TemplateField,但GridView沒有ItemCommand event,取而代之的是RowCommand event。
<%@ Page Language="C#" %>2

3
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">4

5
<script runat="server">6
/* 7
(C) OOMusou 2007 http://oomusou.cnblogs.com8

9
Filename : GridView_RowCommand_RowIndex.aspx10
Compiler : Visual Studio 2005 / C# 2.0 / ASP.NET 2.011
Description : Demo how to get RowIndex in GridView's LinkButton12
Release : 06/26/2007 1.013
*/14
protected void Page_Load(object sender, EventArgs e) {15
if (!IsPostBack)16
GridView1_DataBind();17
}18

19
protected void GridView1_DataBind() {20
SqlDataSource1.ConnectionString = @"Data Source=.\sqlexpress;Initial Catalog=pubs;Integrated Security=True";21
SqlDataSource1.SelectCommand = "SELECT TOP 10 " +22
"fname," +23
"lname " +24
"FROM employee";25
GridView1.DataSourceID = SqlDataSource1.ID;26
GridView1.DataKeyNames = new string[] { "lname" };27
GridView1.AutoGenerateColumns = false;28
}29

30
protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e) {31
if (e.CommandName == "Select") {32
int rowIndex = ((GridViewRow)((LinkButton)e.CommandSource).NamingContainer).RowIndex;33
Label1.Text = GridView1.DataKeys[rowIndex].Value.ToString();34
}35
}36
</script>37

38
<html xmlns="http://www.w3.org/1999/xhtml">39
<head runat="server">40
<title>Untitled Page</title>41
</head>42
<body>43
<form id="form1" runat="server">44
<div>45
<asp:GridView ID="GridView1" runat="server" OnRowCommand="GridView1_RowCommand">46
<Columns>47
<asp:TemplateField HeaderText="First Name">48
<ItemTemplate>49
<asp:LinkButton ID="LinkButton1" runat="server" CommandName="Select" Text='<%#Eval("fname")%>'></asp:LinkButton>50
</ItemTemplate>51
</asp:TemplateField>52
</Columns>53
</asp:GridView>54
</div>55
<asp:Label ID="Label1" runat="server"></asp:Label>56
<asp:SqlDataSource ID="SqlDataSource1" runat="server"></asp:SqlDataSource>57
</form>58
</body>59
</html>
最難理解的應該是32行
int rowIndex = ((GridViewRow)((LinkButton)e.CommandSource).NamingContainer).RowIndex;
e.CommandSource傳的是按下去的LinkButton,不過由於傳回的是Object,就得自行轉成LinkButton,但由於我們想知道的是RowIndex,而LinkButton是包含在GridViewRow內,所以透過NamingContainer傳回目前的GridViewRow,但傳回的是Control,所以需在轉成GridViewRow後才能有RowIndex property。
Conclusion
GridView是DataGrid的繼承人,但不少寫法和DataGrid並不一樣,GridView很多地方比DataGrid更強更好用,但這個例子卻發現GridView比DataGrid麻煩些,或許我沒找到好最好的方法,若有人有更好的方式,歡迎指正,謝謝。



浙公网安备 33010602011771号