关于 C# 中 Asp.net 中的 Gridview 和数据的问题

Question about Gridview and data in Asp.net with C#

我正在制作一个模块以将数组保存在 SQL 数据库中。例如,我想保存 (889,4,01/12/2021)(889,4,02/12/2021)(889,4,03/12/2021).

我正在使用 gridview 获取第一个值 (889)。然后我用文本框获取日期,然后我 运行 查询 return 行中的日期并存储在 gridview 中。

我正在尝试使用 GridView2.Rows[0].Cells[1].Text 选择第二个 gridview 值 (date),但超出了有效值的范围。

因为这是一个数组,所以我将所有 SQL 句子保存在一个文本框中,稍后再执行,这就是我的代码

string[,] arreglo = new string[GridView1.Rows.Count, 7];
foreach (GridViewRow row in GridView1.Rows)
{
    CheckBox chkbox1 = (CheckBox)row.FindControl("chkActive");
    if (chkbox1.Checked)
    {
        arreglo[row.RowIndex, 0] = GridView1.Rows[row.RowIndex].Cells[1].Text;
        string[,] array = new string[GridView2.Rows.Count, 2];
        foreach (GridViewRow col in GridView2.Rows)
            array[col.RowIndex, 0] = GridView2.Rows[col.RowIndex].Cells[1].Text;
        txtInsert.Text = txtInsert.Text + "insert into  T_USUARIO_dETALLE(id_usuario,campana,fecha,fecha_carga,id_superv,estado_dotacion) values ('" + arreglo[row.RowIndex, 0].ToString() + "', '" + lblcampana.Text + "','"+ GridView2.Rows[0].Cells[1].Text  + "','" + LBLSUPERV.Text + "','" + ddlEstado.SelectedValue + "')";
    }
}

感谢帮助!!!

好的,这是 db land 中最经典的设置之一!

我们有一些父记录,对于每条记录,我们需要显示(和编辑)子行。

现在有更多 UI 口味的冰淇淋可供选择。

这表明我们需要“嵌套”主记录(比如在网格中)以显示子记录(我们的第二个网格)。

好吧,事实证明网格真的不能很好地嵌套。

因此,对于父记录,让我们使用 ListView - 它们工作得更好。

好的,所以我们可以启动向导 - 构建 LV,然后在这里使用核武器并删除 + 炸毁所有模板。在我们添加这个的同时,删除额外的嵌套 table。我算了 < 2 分钟的时间。

所以,我们现在有了这个简单的 LV。

    <asp:ListView ID="ListView1" runat="server" DataKeyNames="ID" >
       <ItemTemplate>
          <tr>
            <td><asp:Button ID="cmdView" runat="server" Text="+" /></td>
            <td><asp:Label ID="HotelNameLabel" runat="server" Text='<%# Eval("HotelName") %>' /></td>
            <td><asp:Label ID="CityLabel" runat="server" Text='<%# Eval("City") %>' /></td>
            <td><asp:Label ID="ProvinceLabel" runat="server" Text='<%# Eval("Province") %>' /></td>
            <td><asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' /></td>
          </tr>

           </ItemTemplate>
       <LayoutTemplate>
        <table id="itemPlaceholderContainer" runat="server" class = "table table-hover" >
            <tr runat="server" style="">
                <th runat="server">View</th>
                <th runat="server">HotelName</th>
                <th runat="server">City</th>
                <th runat="server">Province</th>
                <th runat="server">Description</th>
            </tr>
            <tr id="itemPlaceholder" runat="server">
            </tr>
         </table>
       </LayoutTemplate>
    </asp:ListView>

 </div>

我们要填写的代码是这样的:

   protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
            LoadMainGrid();
    }

    void LoadMainGrid()
    {
        string strSQL = "SELECT * FROM tblHotels ORDER BY HotelName";
        ListView1.DataSource = MyRst(strSQL);
        ListView1.DataBind();
    }

我们现在有这个:

好的,现在我们需要子网格。

然后我们将这个作为子网格移动到上面的LV中。

所以,现在我们有了这个标记:

            <td><asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' /></td>
          </tr>

<tr>
<td colspan="5">
    <div id="MyGrid" runat="server" style="display:none;margin-left:1%">

    <div>
    <asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="False" 
        DataKeyNames="ID" CssClass="table table-hover table-responsive borderhide" >
        <Columns>
            <asp:TemplateField HeaderText="First Name">
                <ItemTemplate>
                    <asp:TextBox ID="FirstName" runat="server" Text='<%# Eval("FirstName") %>'  />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Last Name">
                <ItemTemplate>
                    <asp:TextBox ID="LastName" runat="server" Text='<%# Eval("LastName") %>'  />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="City">
                <ItemTemplate>
                    <asp:TextBox ID="City" runat="server" Text='<%# Eval("City") %>'  />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Start date">
                <ItemTemplate>
                    <asp:TextBox ID="dtStart" runat="server" Text='<%# Eval("dtStart", "{0:yyyy-MM-ddTHH:mm}") %>'  TextMode="DateTimeLocal" />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="End date">
                <ItemTemplate>
                    <asp:TextBox ID="dtEnd" runat="server" Text='<%# Eval("dtEnd","{0:yyyy-MM-ddTHH:mm}") %>' TextMode="DateTimeLocal" />
                </ItemTemplate>
            </asp:TemplateField>
        
           
        </Columns>
        
    </asp:GridView>
    </div>

        <div style="float:right;margin-right:-10px">
        <asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" OnClick="cmdSave_Click"  />
        <asp:Button ID="cmdAdd" runat="server" Text="Add New Row" CssClass="btn" style="margin-left:5px" OnClick="cmdAdd_Click" />
        </div>
    </div>
</td>

所以我们在 lv 列的标记之后右上角。

现在,我们要做的就是连接“+”按钮展开:

这是 LV 中的第一行按钮

 <td><asp:Button ID="cmdView" runat="server" Text="+"  OnClick="cmdView_Click"/></td>

代码是这样的:

   protected void cmdView_Click(object sender, EventArgs e)
    {
        Button cmd = (Button)sender;
        ListViewDataItem gVR = (ListViewDataItem)cmd.NamingContainer;
        GridView gChild = (GridView)gVR.FindControl("GridView2");   // pluck out the grid for this row
        HtmlGenericControl MyDiv = (HtmlGenericControl)gVR.FindControl("MyGrid");

        //if (gChild.Style["display"] == "normal")
        if (MyDiv.Style["display"] == "normal")
        {
            // if grid is already display, then hide it, and exit
            MyDiv.Style["display"] = "none";
            return;
        }
        MyDiv.Style["display"] = "normal";
        int HotelPK = (int)ListView1.DataKeys[gVR.DataItemIndex]["ID"];

        // only re-load if never loaded
        if (gChild.Rows.Count == 0)
        {
            gChild.DataSource = MyRst("SELECT * from People where hotel_id = " + HotelPK);
            gChild.DataBind();
        }
    }

所以,现在我们有了这个:

好的,现在我们要做的就是创建一个“保存”按钮,用于保存我们对此 GV 所做的任何更改。

这很简单,所以我们放入一个保存按钮,如下所示:

因此,在我们的网格正下方,我们放入:

    </asp:GridView>
    </div>

        <div style="float:right;margin-right:-10px">
        <asp:Button ID="cmdSave" runat="server" Text="Save Edits" CssClass="btn" />
        <asp:Button ID="cmdAdd" runat="server" Text="Add New Row" CssClass="btn" style="margin-left:5px" />
        </div>
    </div>

我们现在有这个:

好的,那么对于按钮,我们添加一个点击事件:

(只需输入 onclick= 并且 intelsense 会提供创建点击事件的功能,看起来什么都没发生,但是转到后面的代码,您会看到偶数存根。

我们使用这个代码:

    protected void cmdSave_Click(object sender, EventArgs e)
    {
        Button cmdSave = (Button)sender;
        ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;

        GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
        int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
        // send grid to table
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            string strSQL = "SELECT * from People WHERE hotel_id = " + HotelID;
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
                SqlCommandBuilder daU = new SqlCommandBuilder(da);

                DataTable rstGrid = new DataTable();
                rstGrid.Load(cmdSQL.ExecuteReader());
                foreach (GridViewRow gRow in MyGrid.Rows)
                {
                    DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
                    OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
                    OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
                    OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
                    string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
                    if (myDate == "")
                        OneRow["dtStart"] = DBNull.Value;
                    else
                        OneRow["dtStart"]= DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);

                    myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
                    if (myDate == "")
                        OneRow["dtEnd"] = DBNull.Value;
                    else
                        OneRow["dtEnd"]  = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
                }
                da.Update(rstGrid);
            }
        }            
    }

好的,我们不妨连接“新行按钮”。

所以对于那个代码我们有这个:

    protected void cmdAdd_Click(object sender, EventArgs e)
    {
        Button cmdNew = (Button)sender;
        ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;

        GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
        int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
        string strSQL = "INSERT INTO People (Hotel_ID) VALUES(" + HotelID + ")";
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                cmdSQL.ExecuteNonQuery();
            }

            DataTable rstGrid = MyRst("SELECT * from People where Hotel_ID = " + HotelID);
            MyGrid.DataSource = rstGrid;
            MyGrid.DataBind();
        }
    }

我还有一个辅助例程 - 它是一个全局函数,对于给定的 sql 字符串,它只是 returns 数据 table。我在上面确实用过几次。

这个例程:

    public DataTable MyRst(string strSQL)
    {
        DataTable rstData = new DataTable();
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                rstData.Load(cmdSQL.ExecuteReader());
            }
        }
        return rstData;
    }

Edit/Upate(使 UI 更好):

一个问题? 如果用户点击添加新行,他们无疑会开始打字,然后很可能再次点击添加新行(但在上面,他们必须先点击保存数据)。

所以,我建议在添加新行之前保存数据。

这迫使我们无论如何都要打破那个更长的例程。

所以我们添加一个“Grid to Table”,然后添加一个“save table”到数据库。将其分成两步不仅修复了上面的“错误”或“问题”,而且实际上减少了代码。

所以,我建议更新这 3 个(以及 4 个)例程,它们都更短,应该使用。

因此,添加行、保存编辑和 MyRst 都已更新。

我建议使用此代码,因此如果用户点击添加行,他们将不会丢失任何现有的编辑,我敢说这很可能会发生。

因此,我建议将此代码用于保存和添加行按钮

   protected void cmdSave_Click(object sender, EventArgs e)
    {
        Button cmdSave = (Button)sender;
        ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;

        GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
        int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
        DataTable rstGrid = MyRst("SELECT * FROM People WHERE Hotel_ID = " + HotelID);
        // send grid to table
        GridToTable(MyGrid, rstGrid);
        // save to database
        SaveGrid(MyGrid, rstGrid);
    }

    protected void cmdAdd_Click(object sender, EventArgs e)
    {
        Button cmdNew = (Button)sender;
        ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;

        GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
        int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
        DataTable rstGrid = MyRst("SELECT * FROM People where Hotel_ID = " + HotelID);
        // send any data edits from Grid to table
        GridToTable(MyGrid, rstGrid);
        // add new row
        DataRow MyNewRow = rstGrid.NewRow();
        MyNewRow["Hotel_ID"] = HotelID;
        rstGrid.Rows.Add(MyNewRow); 
        
        MyGrid.DataSource = rstGrid;
        MyGrid.DataBind();            
        // save data (must do AFTER grid bind - new row!!!)
        SaveGrid(MyGrid, rstGrid);
    }

    void SaveGrid(GridView MyGrid, DataTable rstGrid)
    {
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand(rstGrid.TableName, conn))
            {
                conn.Open();
                SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
                SqlCommandBuilder daU = new SqlCommandBuilder(da);
                da.Update(rstGrid);
            }
        }
    }

    void GridToTable(GridView MyGrid, DataTable rstGrid)
    {
        foreach (GridViewRow gRow in MyGrid.Rows)
        {
            DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
            OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
            OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
            OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
            string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
            if (myDate == "")
                OneRow["dtStart"] = DBNull.Value;
            else
                OneRow["dtStart"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);

            myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
            if (myDate == "")
                OneRow["dtEnd"] = DBNull.Value;
            else
                OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
        }
    }

    public DataTable MyRst(string strSQL)
    {
        DataTable rstData = new DataTable();
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                rstData.Load(cmdSQL.ExecuteReader());
                rstData.TableName = strSQL;
            }
        }
        return rstData;
    }

Edit2:不要为 SQL 使用集中字符串?

好吧,注意是真的 - 你永远不会使用“用户输入”!!!

然而,大多数发帖者无法区分,因此有一个版本没有任何 SQL 字符串连接的 where 值。

   protected void cmdView_Click(object sender, EventArgs e)
    {
        Button cmd = (Button)sender;
        ListViewDataItem gVR = (ListViewDataItem)cmd.NamingContainer;
        GridView gChild = (GridView)gVR.FindControl("GridView2");   // pluck out the grid for this row
        HtmlGenericControl MyDiv = (HtmlGenericControl)gVR.FindControl("MyGrid");

        //if (gChild.Style["display"] == "normal")
        if (MyDiv.Style["display"] == "normal")
        {
            // if grid is already display, then hide it, and exit
            //gChild.Style["display"] = "none";
            MyDiv.Style["display"] = "none";
            return;
        }
        //gChild.Style["display"] = "normal";
        MyDiv.Style["display"] = "normal";
        int HotelPK = (int)ListView1.DataKeys[gVR.DataItemIndex]["ID"];

        // only re-load if never loaded
        if (gChild.Rows.Count == 0)
        {
            SqlCommand cmdSQL = new SqlCommand("SELECT * FROM People WHERE Hotel_ID = @ID");
            cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelPK;

            gChild.DataSource = MyRstP(cmdSQL);
            gChild.DataBind();
        }
    }

    protected void cmdSave_Click(object sender, EventArgs e)
    {
        Button cmdSave = (Button)sender;
        ListViewDataItem lvRow = (ListViewDataItem)cmdSave.NamingContainer;

        GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
        int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
        SqlCommand cmdSQL = new SqlCommand("SELECT * FROM People where Hotel_ID = @ID");
        cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelID;
        DataTable rstGrid = MyRstP(cmdSQL);
        // send grid to table
        GridToTable(MyGrid, rstGrid);
        // save to database
        SaveGrid(rstGrid,"People");
    }

    protected void cmdAdd_Click(object sender, EventArgs e)
    {
        Button cmdNew = (Button)sender;
        ListViewDataItem lvRow = (ListViewDataItem)cmdNew.NamingContainer;

        GridView MyGrid = (GridView)lvRow.FindControl("GridView2");
        int HotelID = (int)ListView1.DataKeys[lvRow.DisplayIndex]["ID"];
        SqlCommand cmdSQL = new SqlCommand("SELECT * from People WHERE Hotel_ID = @ID");
        cmdSQL.Parameters.Add("@ID", SqlDbType.Int).Value = HotelID;
        DataTable rstGrid = MyRstP(cmdSQL);
        // send any data edits from Grid to table
        GridToTable(MyGrid, rstGrid);
        // add new row
        DataRow MyNewRow = rstGrid.NewRow();
        MyNewRow["Hotel_ID"] = HotelID;
        rstGrid.Rows.Add(MyNewRow); 
        // save data (must do AFTER grid bind - new row!!!)
        SaveGrid(rstGrid,"People");
        
        MyGrid.DataSource = rstGrid;
        MyGrid.DataBind();            
    }

    void SaveGrid(DataTable rstGrid, string strTable)
    {
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand("SELECT * FROM " + strTable, conn))
            {
                conn.Open();
                SqlDataAdapter da = new SqlDataAdapter(cmdSQL);
                SqlCommandBuilder daU = new SqlCommandBuilder(da);
                da.Update(rstGrid);
            }
        }
    }

    void GridToTable(GridView MyGrid, DataTable rstGrid)
    {
        foreach (GridViewRow gRow in MyGrid.Rows)
        {
            DataRow OneRow = rstGrid.Rows[gRow.RowIndex];
            OneRow["FirstName"] = ((TextBox)gRow.FindControl("FirstName")).Text;
            OneRow["LastName"] = ((TextBox)gRow.FindControl("LastName")).Text;
            OneRow["City"] = ((TextBox)gRow.FindControl("City")).Text;
            string myDate = ((TextBox)gRow.FindControl("dtStart")).Text;
            if (myDate == "")
                OneRow["dtStart"] = DBNull.Value;
            else
                OneRow["dtStart"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);

            myDate = ((TextBox)gRow.FindControl("dtEnd")).Text;
            if (myDate == "")
                OneRow["dtEnd"] = DBNull.Value;
            else
                OneRow["dtEnd"] = DateTime.ParseExact(myDate, "yyyy-MM-ddTHH:mm", null);
        }
    }

    public DataTable MyRst(string strSQL)
    {
        DataTable rstData = new DataTable();
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                rstData.Load(cmdSQL.ExecuteReader());
                rstData.TableName = strSQL;
            }
        }
        return rstData;
    }

    public DataTable MyRstP(SqlCommand cmdSQL)
    {
        DataTable rstData = new DataTable();
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            using (cmdSQL)
            {
                cmdSQL.Connection = conn;
                conn.Open();
                rstData.Load(cmdSQL.ExecuteReader());                    
            }
        }
        return rstData;
    }
}