簡體   English   中英

ASP.NET C# Gridview 拋出索引超出范圍

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM