如何通过单击 asp.net 中的 GridView 列获取单元格索引 - 简单方法
How to get cell index by clicking on GridView column in asp.net - simple method
我知道这个问题已经被问过很多次了,并且由于我对 JS 的了解有限,我已经尝试了所有方法,但我根本无法解决任何问题。所以我将我的数据绑定到 GridView :
Dim dt As DataTable = New DataTable()
dt.Columns.Add(New DataColumn("ID"))
dt.Columns.Add(New DataColumn("NAME"))
dt.Columns.Add(New DataColumn("CITY"))
dt.Columns.Add(New DataColumn("CURRENT JOB"))
dt.Columns.Add(New DataColumn("@COMPANY"))
dt.Columns.Add(New DataColumn("C")) ' communication
dt.Columns.Add(New DataColumn("S")) 'select
Dim ID As String
Dim name As String
Dim city As String
Dim current_job As String
Dim company As String
Dim com As String
For i = 0 To ds.Tables(0).Rows.Count - 1
ID = ds.Tables(0).Rows(i)(1).ToString()
name = ds.Tables(0).Rows(i)(2).ToString()
city = ds.Tables(0).Rows(i)(3).ToString()
current_job = ds.Tables(0).Rows(i)(9).ToString()
company = ds.Tables(0).Rows(i)(10).ToString()
If ds.Tables(0).Rows(i)(12).ToString() = "" Then
com = ""
Else
com = "X"
End If
dt.Rows.Add(ID, name, city, current_job, company, com, "S")
Next
candidate_grid_view.DataSource = dt
candidate_grid_view.DataBind()
我已经注册了单元格点击 candidate_grid_view.OnRowDataBound 事件:
Protected Sub Candidate_OnRowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.Attributes("onclick") = Page.ClientScript.GetPostBackClientHyperlink(candidate_grid_view, "Select$" & e.Row.RowIndex)
e.Row.Attributes("style") = "cursor:pointer"
End If
End Sub
我可以通过 candidate_grid_view.SelectedRow.RowIndex
在 OnSelectedIndexChanged
事件中轻松获取行索引,但我需要列(单元格)的单击事件来注册单元格索引(列索引)。没有cellindex 属性!?
Protected Sub Candidate_OnSelectedIndexChanged(sender As Object, e As EventArgs)
Dim index As Integer = candidate_grid_view.SelectedRow.RowIndex
End Sub
为什么在 VB.NET 中获取列索引如此简单,在 ASP.NET 中却如此复杂?
好吧,连续点击 - 非常简单。
那么,让我们按照我们的方式来解决这个问题。
首先,一个 gv - 像这样的简单标记:
<div style="padding:25px;width:50%">
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="View" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="View" CssClass="btn"
OnClick="cmdView_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
我们要填写的代码是这样的:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid
End If
End Sub
Sub LoadGrid()
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL As String = "SELECT * FROM tblHotelsA ORDER BY HotelName"
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmdSQL.ExecuteReader())
GridView1.DataSource = rstData
GridView1.DataBind()
End Using
End Using
End Sub
Protected Sub cmdView_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
Debug.Print("Row click index = " & gRow.RowIndex)
' get primary key (hidden by datakeys
Dim PKID As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")
Debug.Print("Data base row PKID = " & PKID)
Debug.Print("hotel name of this row = " & gRow.Cells(2).Text)
End Sub
现在,如果我们点击查看按钮(对于行),那么我们将得到:
好的,到目前为止 - 非常简单。
现在,在任意位置单击一行怎么样 - 按钮上没有必要?
哎呀,所有控件?我会转储“单元格”并将标准 asp.net 控件放入该 GV -(就像我对按钮所做的那样)。但是,对于很多列,这会变得很痛苦 -(太多凌乱的“templatefield”标签 - 我不喜欢那些)。
因此,我会转储 GV,并转到列表视图。
但是,让我们通过这种方式强制编写代码。但是,我已经这样做了很长时间 - 从来不需要只获取细胞信息。
但是,你可以说这样做:
在我们的行数据绑定中,只需为每个单元格添加一个点击事件,这样说:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
For i As Integer = 0 To e.Row.Cells.Count - 2 ' skip last button cell
Dim MyCell As TableCell = e.Row.Cells(i)
Dim RowCol As string = e.Row.RowIndex & "," & i
MyCell.Attributes.Add("onclick", "MyClick('" & RowCol & "')")
Next
End If
End Sub
我们所做的只是添加一行和列值。
所以,现在在我们的标记中,我们有这个:
</asp:GridView>
<asp:HiddenField ID="HRowInfo" runat="server" />
<asp:Button ID="cmdRowClick" runat="server" Text="Row click" ClientIDMode="Static"
onclick="cmdRowClick_Click" CommandArgument="0" />
<script>
function MyClick(RowInfo) {
$("#HRowInfo").val(RowInfo)
$('#cmdRowClick').click()
}
</script>
因此,我们将值推入隐藏字段,然后单击我们的按钮 - 只是网格下方的平面简按钮(我们将使用 style="display:none"
隐藏它
后面的代码是这样的:
Protected Sub cmdRowClick_Click(sender As Object, e As EventArgs)
Debug.Print(HRowInfo.Value)
End Sub
现在,当我点击任何单元格时,我得到行、列的输出,如下所示:
从上面,我可以对 Gridview.Rows 进行索引,然后将这两个值作为单元格。
但是,我不相信我们真的 need/want 单元格上的点击事件 - 我们“可能”,但话又说回来,在该表单上放置一些控件可能会更好 - 作为重复网格, 并逐行工作。
如前所述,我倾向于为此使用 ListView。
假设我们有上面的酒店列表,但我希望用户在“单元格”中输入一个值来表示住宿天数。但是网格显示每晚房价,当我输入住宿天数时,我想要另一列显示总费用。
我们可以尝试处理并连接一个单元格,但这种情况非常罕见,我需要这样做。
但是,有了标准控件,它确实变得有些容易。
正如我所说,我从来都不喜欢 GV 做这种事情,但让我们在晚间文本框、晚间费率和总计列上方添加。
(我们最好使用列表视图,但没什么大不了的)。
所以,让我们假设这个标记:
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Nights">
<ItemTemplate>
<asp:TextBox ID="txtNights" runat="server" TextMode="Number"
Text = '<%# Eval("Nights") %>' Width ="40">
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Per night">
<ItemTemplate>
<asp:Label ID="LPrice" runat="server" Text='<%# Eval("Price", "{0:C2}") %>' >
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Total">
<ItemTemplate>
<asp:Label ID="txtAmount" runat="server"
Text='<%# Eval("Tamount", "{0:c}") %>'
width="50"
>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
所以,用相同的代码来填充 -(没有行数据绑定事件)。
好的,现在我们有了这个:
现在,假设我想更改住宿天数。我真的不需要单击单元格,对吗?我只想让用户输入住宿天数,然后说更新总金额。
因此,我们只需向该文本框添加一个 plane jane text changed 事件(和自动 post-back)。
因此,标记变为:
<asp:TemplateField HeaderText="Nights">
<ItemTemplate>
<asp:TextBox ID="txtNights" runat="server" TextMode="Number"
Text = '<%# Eval("Nights") %>' Width ="40"
OnTextChanged="txtNights_TextChanged"
AutoPostBack="true"
>
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
我们现在只需点击网格中的任何“晚”单元格,输入一个新值并点击 Tab,或者移出并点击另一行。
文本更改事件的代码如下所示:
Protected Sub txtNights_TextChanged(sender As Object, e As EventArgs)
Dim txtNights As TextBox = sender
Dim gRow As GridViewRow = txtNights.NamingContainer
Dim lPrice As Label = gRow.FindControl("LPrice")
Dim TotalAmount As Label = gRow.FindControl("txtAmount")
TotalAmount.Text = (lPrice.Text * txtNights.Text).ToString("C2")
End Sub
所以,这就是为什么我建议您通常不需要单元格点击事件。
你“可能”,但在大多数情况下我认为你不会。
我知道这个问题已经被问过很多次了,并且由于我对 JS 的了解有限,我已经尝试了所有方法,但我根本无法解决任何问题。所以我将我的数据绑定到 GridView :
Dim dt As DataTable = New DataTable()
dt.Columns.Add(New DataColumn("ID"))
dt.Columns.Add(New DataColumn("NAME"))
dt.Columns.Add(New DataColumn("CITY"))
dt.Columns.Add(New DataColumn("CURRENT JOB"))
dt.Columns.Add(New DataColumn("@COMPANY"))
dt.Columns.Add(New DataColumn("C")) ' communication
dt.Columns.Add(New DataColumn("S")) 'select
Dim ID As String
Dim name As String
Dim city As String
Dim current_job As String
Dim company As String
Dim com As String
For i = 0 To ds.Tables(0).Rows.Count - 1
ID = ds.Tables(0).Rows(i)(1).ToString()
name = ds.Tables(0).Rows(i)(2).ToString()
city = ds.Tables(0).Rows(i)(3).ToString()
current_job = ds.Tables(0).Rows(i)(9).ToString()
company = ds.Tables(0).Rows(i)(10).ToString()
If ds.Tables(0).Rows(i)(12).ToString() = "" Then
com = ""
Else
com = "X"
End If
dt.Rows.Add(ID, name, city, current_job, company, com, "S")
Next
candidate_grid_view.DataSource = dt
candidate_grid_view.DataBind()
我已经注册了单元格点击 candidate_grid_view.OnRowDataBound 事件:
Protected Sub Candidate_OnRowDataBound(sender As Object, e As System.Web.UI.WebControls.GridViewRowEventArgs)
If e.Row.RowType = DataControlRowType.DataRow Then
e.Row.Attributes("onclick") = Page.ClientScript.GetPostBackClientHyperlink(candidate_grid_view, "Select$" & e.Row.RowIndex)
e.Row.Attributes("style") = "cursor:pointer"
End If
End Sub
我可以通过 candidate_grid_view.SelectedRow.RowIndex
在 OnSelectedIndexChanged
事件中轻松获取行索引,但我需要列(单元格)的单击事件来注册单元格索引(列索引)。没有cellindex 属性!?
Protected Sub Candidate_OnSelectedIndexChanged(sender As Object, e As EventArgs)
Dim index As Integer = candidate_grid_view.SelectedRow.RowIndex
End Sub
为什么在 VB.NET 中获取列索引如此简单,在 ASP.NET 中却如此复杂?
好吧,连续点击 - 非常简单。
那么,让我们按照我们的方式来解决这个问题。
首先,一个 gv - 像这样的简单标记:
<div style="padding:25px;width:50%">
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="View" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Button ID="cmdView" runat="server" Text="View" CssClass="btn"
OnClick="cmdView_Click" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
我们要填写的代码是这样的:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadGrid
End If
End Sub
Sub LoadGrid()
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL As String = "SELECT * FROM tblHotelsA ORDER BY HotelName"
Using cmdSQL As New SqlCommand(strSQL, conn)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmdSQL.ExecuteReader())
GridView1.DataSource = rstData
GridView1.DataBind()
End Using
End Using
End Sub
Protected Sub cmdView_Click(sender As Object, e As EventArgs)
Dim btn As Button = sender
Dim gRow As GridViewRow = btn.NamingContainer
Debug.Print("Row click index = " & gRow.RowIndex)
' get primary key (hidden by datakeys
Dim PKID As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")
Debug.Print("Data base row PKID = " & PKID)
Debug.Print("hotel name of this row = " & gRow.Cells(2).Text)
End Sub
现在,如果我们点击查看按钮(对于行),那么我们将得到:
好的,到目前为止 - 非常简单。
现在,在任意位置单击一行怎么样 - 按钮上没有必要?
哎呀,所有控件?我会转储“单元格”并将标准 asp.net 控件放入该 GV -(就像我对按钮所做的那样)。但是,对于很多列,这会变得很痛苦 -(太多凌乱的“templatefield”标签 - 我不喜欢那些)。
因此,我会转储 GV,并转到列表视图。
但是,让我们通过这种方式强制编写代码。但是,我已经这样做了很长时间 - 从来不需要只获取细胞信息。
但是,你可以说这样做:
在我们的行数据绑定中,只需为每个单元格添加一个点击事件,这样说:
Protected Sub GridView1_RowDataBound(sender As Object, e As GridViewRowEventArgs) Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
For i As Integer = 0 To e.Row.Cells.Count - 2 ' skip last button cell
Dim MyCell As TableCell = e.Row.Cells(i)
Dim RowCol As string = e.Row.RowIndex & "," & i
MyCell.Attributes.Add("onclick", "MyClick('" & RowCol & "')")
Next
End If
End Sub
我们所做的只是添加一行和列值。
所以,现在在我们的标记中,我们有这个:
</asp:GridView>
<asp:HiddenField ID="HRowInfo" runat="server" />
<asp:Button ID="cmdRowClick" runat="server" Text="Row click" ClientIDMode="Static"
onclick="cmdRowClick_Click" CommandArgument="0" />
<script>
function MyClick(RowInfo) {
$("#HRowInfo").val(RowInfo)
$('#cmdRowClick').click()
}
</script>
因此,我们将值推入隐藏字段,然后单击我们的按钮 - 只是网格下方的平面简按钮(我们将使用 style="display:none"
隐藏它后面的代码是这样的:
Protected Sub cmdRowClick_Click(sender As Object, e As EventArgs)
Debug.Print(HRowInfo.Value)
End Sub
现在,当我点击任何单元格时,我得到行、列的输出,如下所示:
从上面,我可以对 Gridview.Rows 进行索引,然后将这两个值作为单元格。
但是,我不相信我们真的 need/want 单元格上的点击事件 - 我们“可能”,但话又说回来,在该表单上放置一些控件可能会更好 - 作为重复网格, 并逐行工作。
如前所述,我倾向于为此使用 ListView。
假设我们有上面的酒店列表,但我希望用户在“单元格”中输入一个值来表示住宿天数。但是网格显示每晚房价,当我输入住宿天数时,我想要另一列显示总费用。
我们可以尝试处理并连接一个单元格,但这种情况非常罕见,我需要这样做。
但是,有了标准控件,它确实变得有些容易。
正如我所说,我从来都不喜欢 GV 做这种事情,但让我们在晚间文本框、晚间费率和总计列上方添加。
(我们最好使用列表视图,但没什么大不了的)。
所以,让我们假设这个标记:
<asp:GridView ID="GridView1" runat="server"
AutoGenerateColumns="False" DataKeyNames="ID" CssClass="table">
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="Description" HeaderText="Description" />
<asp:TemplateField HeaderText="Nights">
<ItemTemplate>
<asp:TextBox ID="txtNights" runat="server" TextMode="Number"
Text = '<%# Eval("Nights") %>' Width ="40">
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Per night">
<ItemTemplate>
<asp:Label ID="LPrice" runat="server" Text='<%# Eval("Price", "{0:C2}") %>' >
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Total">
<ItemTemplate>
<asp:Label ID="txtAmount" runat="server"
Text='<%# Eval("Tamount", "{0:c}") %>'
width="50"
>
</asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
所以,用相同的代码来填充 -(没有行数据绑定事件)。
好的,现在我们有了这个:
现在,假设我想更改住宿天数。我真的不需要单击单元格,对吗?我只想让用户输入住宿天数,然后说更新总金额。
因此,我们只需向该文本框添加一个 plane jane text changed 事件(和自动 post-back)。
因此,标记变为:
<asp:TemplateField HeaderText="Nights">
<ItemTemplate>
<asp:TextBox ID="txtNights" runat="server" TextMode="Number"
Text = '<%# Eval("Nights") %>' Width ="40"
OnTextChanged="txtNights_TextChanged"
AutoPostBack="true"
>
</asp:TextBox>
</ItemTemplate>
</asp:TemplateField>
我们现在只需点击网格中的任何“晚”单元格,输入一个新值并点击 Tab,或者移出并点击另一行。
文本更改事件的代码如下所示:
Protected Sub txtNights_TextChanged(sender As Object, e As EventArgs)
Dim txtNights As TextBox = sender
Dim gRow As GridViewRow = txtNights.NamingContainer
Dim lPrice As Label = gRow.FindControl("LPrice")
Dim TotalAmount As Label = gRow.FindControl("txtAmount")
TotalAmount.Text = (lPrice.Text * txtNights.Text).ToString("C2")
End Sub
所以,这就是为什么我建议您通常不需要单元格点击事件。
你“可能”,但在大多数情况下我认为你不会。