[英]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.