[英]ASP.NET C# Gridview throwing Index out of range
我正在开发一个用户控件,该控件显示来自网格视图上的 SQL 表的可用存储,供用户选择和填充文本框。 目前我能够将所有内容正确地数据绑定到 gridview 并使用每行内的选择按钮运行操作。 我目前的问题是使用“rows [index]”时我无法将单元格值返回到变量中。 当我达到这一点时,即使我的索引值在调试时是正确的,我也会得到一个 Index is out of range 错误。 出于实验目的,我在不同的迭代中为索引手动设置了 0 和 1 值,但我仍然得到错误,就好像我的 gridview 不包含任何行一样。
我选择行的方法是使用带有由 ButtonField 触发的 OnRowCommand 的 Gridview。
查看其他一些类似的问题和答案,我发现大多数问题是人们获得负值或不使用 DataKeyNames,但这不是我的情况。 我仍然无法修复此错误
我的gridview代码是这样的:
<asp:GridView ID="gvStore" runat="server" AutoGenerateColumns="False" Visible="false" DataKeyNames="Name" OnRowCommand="gvExecSelectSTR_RowCommand">
<Columns>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:ButtonField ButtonType="Link" Text="Select" CommandName="SelectStore"/>
</Columns>
</asp:GridView>
我的按钮操作
protected void gvExecSelectSTR_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "SelectStore")
{
int index = Convert.ToInt32(e.CommandArgument); //Up to this point i get correct row number for index
GridViewRow row = gvStore.Rows[index]; //This row triggers my error
IDStore.Text = row.Cells[0].Text;
}
}
此外,这是我用来将所有内容数据绑定到我的 GridView 的方法
private void GridViewStore()
{
try
{
DataTable StoreTable = new DataTable();
StoreTable.Columns.AddRange(new DataColumn[1]
{
new DataColumn("Name",typeof(string))
});
//Can't show internal SQL commands for this but here i read and load
the SQLscript that selects the table and load it into the reader variable "readerStore"//
if (readerStore.HasRows)
{
while (readerStore.Read())
{
StoreTable.Rows.Add(readerStore["Name"].ToString());
}
}
gvStore.DataSource = StoreTable;
gvStore.DataBind();
readerStore.Close();
}
catch (Exception ex)
{
OnErrorOccurred(new ErrorOccurredEventArgs("Grid View Bind Message" + ex.Message, ex));
}
}
我有什么设置错误吗?
你试过而不是
GridViewRow row = gvStore.Rows[index];
这样做
GridViewRow row = (GridViewRow)gvStore.Rows[e.RowIndex];
为什么要打扰行命令? 你真的不需要那个事件模型,而且在大多数情况下,它只会导致额外的痛苦。
如果您在单击按钮时需要一个行 PK id? 然后使用数据键。 Datakeys 非常好有几个原因。
对于列表中的顶部,将数据库 PK 暴露给客户端总是一个巨大的安全漏洞。 (标记可能会被弄乱,因此您现在使用的数据库 ID 可能是标记中更改的任何内容。
所以,简单的网格视图是这样说的:
<asp:GridView ID="GHotels" runat="server" CssClass="table" AutoGenerateColumns="false"
width="50%" DataKeyNames="ID" >
<Columns>
<asp:BoundField DataField="FirstName" HeaderText="FirstName" />
<asp:BoundField DataField="LastName" HeaderText="LastName" />
<asp:BoundField DataField="HotelName" HeaderText="HotelName" />
<asp:BoundField DataField="Description" HeaderText="Description" ItemStyle-Width="270" />
<asp:TemplateField HeaderText = "View" ItemStyle-HorizontalAlign ="Center" >
<ItemTemplate>
<asp:Button ID="cmdRow" runat="server" Text="View"
CssClass="btn" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
请注意,上面“ID”中的数据键设置是我们的行 PK id,非常好的是我们没有,显示,随时在标记中显示 PK 行 id !!!
然后要填写的代码是这样的:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadData();
}
void LoadData()
{
using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
{
string strSQL =
"SELECT * FROM tblHotelsA ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
{
DataTable rstData = new DataTable();
conn.Open();
rstData.Load(cmdSQL.ExecuteReader());
GHotels.DataSource = rstData;
GHotels.DataBind();
}
}
}
我们现在有了这个:
现在,我们需要一个按钮的点击事件。 对于大多数按钮,您只需双击按钮即可添加/连接事件。 但是,由于按钮在 GV 内部,所以我们不能这样做。 但是我们仍然可以通过标记添加事件。
因此,在 onclick="" 的标记类型中执行此操作时,intel-sense 会弹出创建事件的选项。 像这样说:
(在引号下,按 ctrl-space 以弹出该 Intel-sense 对话框)。
好的,选择创建新事件。
现在,翻到后面的代码,该按钮应该有一个简单的单击事件。
因此,使用此代码:
protected void cmdRow_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
GridViewRow gRow = btn.NamingContainer as GridViewRow;
Debug.Print("Row index click = " + gRow.RowIndex);
Debug.Print("ID (data keys) = " + GHotels.DataKeys[gRow.RowIndex]["ID"].ToString());
Debug.Print("FirstName = " + gRow.Cells[0].Text);
Debug.Print("Last Name = " + gRow.Cells[1].Text);
}
输出:
因此,通过这个简单的设置:
如果我在 GV 上有多个按钮,那么可以获得一个简单的单独单击事件和代码存根。 没有凌乱的行命令(然后检查一些行命令参数)。
我很容易得到行索引。
我得到了从不暴露数据库 PK id 背后的代码(来自 datakeys)
我可以自由地从当前行获取/抓取任何单元格值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.