首页 > 解决方案 > 从有多个页面的 Gridview 中选择数据

问题描述

在我的 gridview 中,我有多个页面。我可以从第 1 页中选择一项或多项并将其保存在 sql 数据库中。但是,如果我从 Page 1 中选择一个项目,从 Page 2中选择另一个项目,系统只会保存Page 1中的项目。

aspx.cs

protected void Page_Load(object sender, EventArgs e)
{
if (Session["UserName"].ToString() != null)
{
    SUserName.Text = Session["UserName"].ToString();
    SUserEmail.Text = Session["Email"].ToString();
}
if (!Page.IsPostBack)
{
    LoadUserSubSection();
    CurrentDate();
    this.SearchItems();
}
}


protected void RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
    e.Row.Attributes.Add("onmouseover", "MouseEvents(this, event)");
    e.Row.Attributes.Add("onmouseout", "MouseEvents(this, event)");
}
 //added in               
 GridViewRow gvr = e.Row;
if (gvr.RowType == DataControlRowType.DataRow)
 {
    CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;

    if (chkSelect != null)
    {
        int StID = Convert.ToInt32(gvItemDesc.DataKeys[gvr.RowIndex]["StID"]);

        chkSelect.Checked = this.StItemDescIDs.Contains(StID);
       }
     }
   }
  private void SearchItems()
 {
  using (SqlConnection con = new SqlConnection(cs))
  {
    using (SqlCommand cmd = new SqlCommand())
    {
        string sql = "SELECT [StID],[StNo],[StItemDesc],[CreatedBy] FROM [StationeryRequest]. 
          [dbo].[tblStationeryItemlist]";
        if (!string.IsNullOrEmpty(txtSearch.Text.Trim()))
        {
            sql += " WHERE StItemDesc LIKE @StItemDesc + '%'";
            cmd.Parameters.AddWithValue("@StItemDesc", txtSearch.Text.Trim());
        }
        cmd.CommandText = sql;
        cmd.Connection = con;
        using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
        {
            DataTable dt = new DataTable();
            sda.Fill(dt);
            gvItemDesc.DataSource = dt;
            gvItemDesc.DataBind();
          }
        }
      }
    }

   private List<int> StItemDescIDs
    {
     get
     {
    if (this.ViewState["StItemDescIDs"] == null)
       {
        this.ViewState["StItemDescIDs"] = new List<int>();
       }

        return this.ViewState["StItemDescIDs"] as List<int>;
         }
       }

   protected void SelectDeselect(object sender, CommandEventArgs e)
    {
       foreach (GridViewRow gvr in gvItemDesc.Rows)
     {
         CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;

         if (chkSelect != null)
        {
          chkSelect.Checked = e.CommandName.Equals("SelectAll");
       }
      }
    }

    protected void OnPaging(object sender, GridViewPageEventArgs e)
    {
 //added in
    foreach (GridViewRow gvr in gvItemDesc.Rows)
    {
      CheckBox chkSelect = gvr.FindControl("chkSelect") as CheckBox;

    if (chkSelect != null)
    {
        int StID = Convert.ToInt32(gvItemDesc.DataKeys[gvr.RowIndex]["StID"]);

        if (chkSelect.Checked && !this.StItemDescIDs.Contains(StID))
        {
            this.StItemDescIDs.Add(StID);
        }
        else if (!chkSelect.Checked && this.StItemDescIDs.Contains(StID))
           {
            this.StItemDescIDs.Remove(StID);
           }
         }
       }    
         gvItemDesc.PageIndex = e.NewPageIndex;
       this.SearchItems();
      }

      protected void Search(object sender, EventArgs e)
     {
       this.SearchItems();
     }

提交 btn

       protected void btnSubmit(object sender, EventArgs e)
        {

            object id;
           //insert into Main Parent table -> tblStationeryRequest
           string insertCmdtblStationeryRequest = "INSERT INTO tblStationeryRequest 
           (Department,RequestFor,UserName,Date,Email,Status) " +
          "output inserted.StReqID " + //Get auto increment for StReqID
         "VALUES (@Department,@RequestFor,@UserName,@Email,@Date,@Status)";
         string Status = "Pending";

    using (SqlConnection conn = new SqlConnection(cs))
    {
    conn.Open();
    using (SqlCommand sqlcmd = new SqlCommand(insertCmdtblStationeryRequest, conn))
    {
        sqlcmd.Parameters.AddWithValue("@Department", ddlDept.SelectedItem.Text);
        sqlcmd.Parameters.AddWithValue("@RequestFor", ddlName.SelectedItem.Text);
        sqlcmd.Parameters.AddWithValue("@Date", lblCurrentDate.Text);
        sqlcmd.Parameters.AddWithValue("@UserName", SUserName.Text);
        sqlcmd.Parameters.AddWithValue("@Email", SUserEmail.Text);

        sqlcmd.Parameters.AddWithValue("@Status", Status);
        //get id from auto increment and will be used it in Child tables -> tblItemRequest, 
          tblSupplierRequest and so on.
        //sqlcmd.ExecuteNonQuery();
        id = sqlcmd.ExecuteScalar(); //the result is of Object type, cast it safely
      }
   }

     Debug.WriteLine(id.ToString()); // Access it like this

  string lblStID = "";

  foreach (GridViewRow row in gvItemDesc.Rows)
   {
    CheckBox status = (row.Cells[1].FindControl("chkSelect") as CheckBox);
    if (status.Checked)
    {
        if (lblStID != "")
        {
            lblStID += ",";
        }
        lblStID += (row.Cells[1].FindControl("chkSelect") as CheckBox).Text;

       }

   }
//In Page 1, can select one or more items 
//However Page 1 one item and Page 2 one time, it only save from Page 1

     string insertCmdtblRequestItemListID = "INSERT INTO tblRequestItemListID(StReqID, StID, 
     StItemDesc) select " + id.ToString() + ",StID,StItemDesc from tblStationeryItemlist where 
    StID in (" + lblStID + ")";

      using (SqlConnection conn = new SqlConnection(cs))
    {
    conn.Open();
    using (SqlCommand sqlcmd = new SqlCommand(insertCmdtblRequestItemListID, conn))
        sqlcmd.ExecuteNonQuery();
      }

.aspx

这是我的网格视图

       < asp:GridView ID = "gvItemDesc" runat = "server" AutoGenerateColumns = "false" 
         AllowPaging = "true" DataKeyNames = "StID" OnPageIndexChanging = "OnPaging" 
         OnRowDataBound = "RowDataBound" Font - Size = "11pt" >
       < Columns >
       < asp:TemplateField >
       < HeaderTemplate >
                        //no need use Check all function
       < asp:CheckBox ID = "checkAll" runat = "server" Text = '<%#Eval("StID") %>' onclick 
        ="checkAll(this);" />
       </ HeaderTemplate >
       < ItemTemplate >
       < asp:CheckBox ID = "chkSelect" runat = "server" Text ='<%# Eval("StID") %>' onclick = 
         "Check_Click(this)" />
       </ ItemTemplate >
       </ asp:TemplateField >
        < asp:BoundField DataField = "StID" HeaderText = "StID" ItemStyle - Width = "150" 
         SortExpression = "StID" Visible = "false" />  

       < asp:BoundField DataField = "StItemDesc" HeaderText = "Item Description" ItemStyle - 
         Width = "150" />
        <asp:TemplateField HeaderText = "" >
        </ asp:TemplateField >
        < asp:TemplateField HeaderText = "" >
        < ItemTemplate >
        < asp:Label ID ="lblStItemDesc" runat = "server" Text = '<%# Eval("StItemDesc") %>' 
         Visible ="false" > </ asp:Label >
           </ ItemTemplate >
          </ asp:TemplateField >
           </ Columns >
             </ asp:GridView >

在此处输入图像描述

标签: c#asp.netgridview

解决方案


好的,这里有两种方法。

首先,您可以在导航、过滤或分页期间让用户选择数据并更新数据库(除非那是您真正想要的???)。

你想要什么:

用户可以选择页面上的任何旧行。也许为了好玩翻页,多选几行。

此时,您可以处理选定的行并更新实际数据库。

所以,我们想把这两个概念“分开”,让你在脑海中一目了然。

接下来:

我们有两个实际的选择。我们因网格中的复选框而遭受回发。我经常使用它,而且还没有那么糟糕。

如果您真的想避免回发,那么在分页事件和最终提交按钮上,您都必须“管理”该检查列表。

让我们和Easy先生一起去吧。如果你真的需要第二种方法,那么我可以发布一个解决方案,但是当/如果你不需要时不需要做额外的工作。

因此,我们的简单网格 - 注意复选框是如何未绑定的 - 没有数据源。

所以,我们的网格:

   <asp:GridView ID="GVHotels" runat="server" AutoGenerateColumns="False" 
            DataKeyNames="ID" CssClass="table" AllowPaging="true" 
            OnPageIndexChanging="GVHotels_PageIndexChanging" OnRowDataBound="GVHotels_RowDataBound">
            <Columns>
                <asp:BoundField DataField="FirstName"   HeaderText="FirstName" />
                <asp:BoundField DataField="LastName"    HeaderText="LastName"  />
                <asp:BoundField DataField="City"        HeaderText="City" />
                <asp:BoundField DataField="HotelName"   HeaderText="HotelName"  />
                <asp:BoundField DataField="Description" HeaderText="Description"  />

                <asp:TemplateField HeaderText="To Process" ItemStyle-HorizontalAlign="Center">
                    <ItemTemplate>
                        <asp:CheckBox ID="chkSel" runat="server" CssClass="bigcheck"
                         OnCheckedChanged="chkSel_CheckedChanged"
                         AutoPostBack="true" />
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
            <PagerStyle CssClass="GridPager" />
        </asp:GridView>
            <asp:Button ID="cmdProcess" runat="server" Text="Process selected" CssClass="btn" OnClick="cmdProcess_Click"  />
            <br />

填充网格的代码:

    List<int> MySelList = new List<int>();
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            LoadGrid();
            ViewState["MySelect"] = MySelList;
        }
        else
            MySelList = (List<int>)ViewState["MySelect"];
    }

    void LoadGrid()
    {
        using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
        {
            string strSQL = "SELECT * FROM tblHotels " + 
                            "WHERE Description is not null " +
                            "ORDER BY HotelName";

            using (SqlCommand cmdSQL = new SqlCommand(strSQL, conn))
            {
                conn.Open();
                DataTable rst = new DataTable();
                rst.Load(cmdSQL.ExecuteReader());
                GVHotels.DataSource = rst;
                GVHotels.DataBind();
            }
        }
    }

我们现在有了这个:

在此处输入图像描述

好的,所以现在我们需要两个额外的例程。

从列表中添加/删除选定检查的代码(我们保留)。

该复选框具有 auto post-back = true,因此该复选框的代码是这个简单的存根:

   protected void chkSel_CheckedChanged(object sender, EventArgs e)
    {
        CheckBox chk = (CheckBox)sender;
        GridViewRow gRow = (GridViewRow)chk.Parent.Parent;
        int pkID = (int)GVHotels.DataKeys[gRow.RowIndex]["ID"];

        if (chk.Checked)
        {
            // add to sel list
            if (!MySelList.Contains(pkID))
               MySelList.Add(pkID);
        }
        else
            MySelList.Remove(pkID);
    }

好的,这将为我们管理选定的复选框。

现在,我们还需要更新显示(显示选择了哪些行)。

    protected void GVHotels_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            CheckBox chk = (CheckBox)e.Row.FindControl("chkSel");
            int pkID = (int)GVHotels.DataKeys[e.Row.RowIndex]["ID"];
            chk.Checked = MySelList.Contains(pkID);
        }
    }

好的,我们已经完成了很多。用户现在可以自由翻页 - 选择他们想要处理的任何行。这个技巧对于某些类型的报告非常有用,或者其他什么类型的报告。您可以呈现网格 - 让用户选择/选择,然后说将该结果用于报告、图表或其他任何内容的过滤器。

所以,现在,当用户点击上面的“进程”按钮时(可能是任何东西)。

让我们为用户选择的酒店更新“活动”列 = true。

因此,我们的“进程”按钮代码可能是这样的:

    protected void cmdProcess_Click(object sender, EventArgs e)
    {
        if (MySelList.Count >0)
        {
            string sWhere = " ID in (" + string.Join(",", MySelList) + ")";

            string strSQL = "UPDATE tblHotels SET Active = 1 WHERE "  + sWhere;

            using (SqlConnection conn = new SqlConnection(Properties.Settings.Default.TEST4))
            using (SqlCommand cmdSQL = new SqlCommand(strSQL))
            {
                conn.Open();
                cmdSQL.ExecuteNonQuery();
            }
            // Clear our select list
            MySelList = new List<int>();
        }
    }

所以,上面的内容很好,因为我们不必为这个选择过程更新数据库,而且通常这不是我们的目标。但是,如上所示,将列表应用于某些代码以更新数据库相当容易。

还要注意非常小心,我不显示,也不显示该 GV 中的数据库 PK id。我不必这样做,因为我们为此目的提供了 DataKeys 功能。非常棒的是,DataKeys 是 100% 自动托管的服务器端,并且密钥列表不会在客户端浏览器中以纯文本形式公开。(因此,安全性要好得多)。而且由于这些数据键不是基于用户输入的——所以我可以使用简单的字符串连接作为标准。如果我使用了输入,甚至是来自 GV 的公开列,那么我们将面临 sql 注入问题 - 但上面不存在任何问题,因为我们没有使用 GV 中的任何显示列。

如前所述,如果您真的无法回复,那么我们可以将此代码移动到最终提交按钮,但在寻呼机事件中也会有代码。但是,我认为由于用户必须四处翻页时会发生回发,因此为每个复选框事件进行回发并不是什么大不了的事。如前所述,您始终可以将网格放在更新面板中,但即便如此,在大多数情况下,您仍会发现上述工作正常。

另一方面,如果您真的希望在移动时更新数据?然后我们可以转储 MySel 列表代码,并简单地将复选框绑定到数据库行。然后在分页时我们可以更新数据库。如果用户选择了一些行/复选框并且不分页,那么问题就变成了会发生什么?换句话说,我们几乎可以肯定在网格下方有一个最终按钮可以继续?正确的?所以,我们可以更新分页,但你必须弄清楚如果他们选择会发生什么,而不是分页?如果有一些最后的按钮可以点击,那么我们再次回到我上面的工作示例。


推荐阅读