Gridview 删除按钮 - 对象引用错误

Gridview Delete Button - Object Reference Error


我正在尝试使用 GridView 在 asp.NET 中开发网页。我希望 GridView 有一个编辑和删除按钮。以下是我对 GridView 的标记:
<asp:GridView ID="EduGrid" CssClass="edugrid table table-striped table-hover table-borderless" runat="server" AutoGenerateColumns="False" GridLines="None" OnRowDeleted="EduGrid_RowDeleted" OnRowDeleting="EduGrid_RowDeleting">
    <Columns>
                 <asp:CommandField SelectText="" ShowSelectButton="True" ControlStyle-CssClass="btn btn-dark btn-sm fa fa-edit" />
                 <asp:CommandField DeleteText="" ShowDeleteButton="true" ControlStyle-CssClass="btn btn-dark btn-sm fa fa-trash" />
                 <asp:BoundField DataField="degree" HeaderText="Degree" SortExpression="degree" />
                 <asp:BoundField DataField="major" HeaderText="Major" SortExpression="major" />
                 <asp:BoundField DataField="year" HeaderText="Passing Year" SortExpression="year" />
                 <asp:BoundField DataField="total marks" HeaderText="Total Marks" SortExpression="total marks" />
                 <asp:BoundField DataField="obt marks" HeaderText="Obtained Marks" SortExpression="obt marks" />
                 <asp:BoundField DataField="division" HeaderText="Division" SortExpression="division" />
                 <asp:BoundField DataField="board" HeaderText="Board/University" SortExpression="board" />
    </Columns>
                                
    <HeaderStyle CssClass="thead-dark" Font-Names="Calibri" Font-Size="Larger" />
    <RowStyle Font-Names="calibri" Font-Size="Medium" />
</asp:GridView>

我在“CandId”页面上也有一个标签,其中包含用于在 GridView 中获取记录并从数据库中删除记录的 ID。但是,由于每个候选人有超过 1 条记录,我想删除基于 2 个参数的记录,即 ID 和学位(第一列)。它仅根据 ID 删除,但删除该特定 ID 的所有记录,但我只想删除一个特定条目。如果我提供学位列作为参数,它会给出一个对象引用异常。以下是我在 c# 中的后端代码:

        protected void EduGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
        {
            GridViewRow row = EduGrid.SelectedRow;
            conn = new SqlConnection(connString);
            string query = "DELETE FROM [Edu Info] WHERE cnic = @cnic AND degree = @degree";
            sqlcmd = new SqlCommand(query, conn);
            sqlcmd.Parameters.AddWithValue("@cnic", lblID.Text);
            sqlcmd.Parameters.AddWithValue("@degree", row.Cells[1].Text);

            try
            {
                conn.Open();
                sqlcmd.ExecuteNonQuery();
                lblInfo.Text = "Record deleted successfully.";
                lblInfo.Visible = true;
                Get_Edu();
            }

            catch (Exception ex)
            {
                lblInfo.Text = "An error occurred. Please contact the administrator.";
                lblInfo.Visible = true;
            }

            finally
            {
                conn.Close();
                conn.Dispose();
                SqlConnection.ClearAllPools();
            }
        }

我认为问题在于 OnRowDeleting 方法不适合与 GridView.SelectedRow 一起使用,并且 .SelectedRow 只能在 OnSelectedIndexChanged 方法中使用。如果是这种情况并且我是对的,我应该怎么做才能解决它?谁能提供解决方案?
谢谢

好的,这里有很多问题。而且我不清楚为什么您的数据源不包含数据库的主键。因此,您不需要同时使用 cnic 和 degree 来标识一行。我不记得在没有 PK ID 的网格中有行。 (所以,你这边很奇怪)。

但是,请记住删除事件不会更改所选索引。事实上,如果你说一个按钮,使用 commandName/CommandText,你会发现行命令首先触发(选定的索引尚未更改),然后选定的索引事件触发。

在您的示例中 - 索引不会更改。

但是,在那种情况下,您可以通过以下方式点击行:

e.RowIndex

所以,你现在可以这样了:

GridViewRow row = EduGrid.Rows[e.RowIndex];

所以,你所拥有的其余部分应该没问题。因此,请记住,对于命令按钮和网格中的大多数按钮,选定的索引(如果要触发)实际上在按钮事件存根之后触发。在某些情况下,理论上您可以将代码移动到选定的索引更改事件 - 但在这种情况下甚至不会触发。所以选定的索引不可用。使用 e.RowIndex 获取该行。

此外,如果您包含数据库中的主键,则无需使用这两列来标识数据库中的该行,而只需使用主键行 ID。而且您甚至不必在网格中显示 PK。

这就是 DataKeyNames = "PK 行列名称" 的用途

例如:

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
            DataKeyNames="ID" >

所以,DataKeyNames = "PK FROM database"

因此在上面的RowDeleting事件中,那么

e.RowIndex - gets you row index clicked on
e.Keys["ID"]  - gets you database PK

因此,请注意您可以(应该)如何尝试从数据库中设置 DataKeyNames = "primary key"。然后你可以用 e.Keys["ID"] 得到 PK 行 id。