c# - 从有多个页面的 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 >
解决方案
好的,这里有两种方法。
首先,您可以在导航、过滤或分页期间让用户选择数据并更新数据库(除非那是您真正想要的???)。
你想要什么:
用户可以选择页面上的任何旧行。也许为了好玩翻页,多选几行。
此时,您可以处理选定的行并更新实际数据库。
所以,我们想把这两个概念“分开”,让你在脑海中一目了然。
接下来:
我们有两个实际的选择。我们因网格中的复选框而遭受回发。我经常使用它,而且还没有那么糟糕。
如果您真的想避免回发,那么在分页事件和最终提交按钮上,您都必须“管理”该检查列表。
让我们和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 列表代码,并简单地将复选框绑定到数据库行。然后在分页时我们可以更新数据库。如果用户选择了一些行/复选框并且不分页,那么问题就变成了会发生什么?换句话说,我们几乎可以肯定在网格下方有一个最终按钮可以继续?正确的?所以,我们可以更新分页,但你必须弄清楚如果他们选择会发生什么,而不是分页?如果有一些最后的按钮可以点击,那么我们再次回到我上面的工作示例。
推荐阅读
- c - 如何通过C中的结构变量对数组**进行排序?
- r - 为什么我在做 KNN 的混淆矩阵中得到 NA?
- android - 无法使用 Flutter 连接到 wss
- spring - 升级spring data mongo db版本
- python - 从输入访问字典内的列表
- python - 如何有效地计算 Python 列表中的每个元素?
- php - Laravel 6 config()->get('database.connections.mysql') 不匹配 DB:connection()
- swift - SwiftUI:什么替代了 Delegate 协议?
- php - 在错误页面上显示表单错误并在 Laravel 中进行验证
- regex - 所有英国车牌格式的 RegEX 验证