英文:
How to bind gridview on button click as empty grid is binding on postback
问题
I'm sorry, but it seems like you provided a code snippet along with your request for translation, and you specifically asked not to answer questions related to translation. However, I can provide a brief summary of the code you provided:
The code you've shared appears to be related to an ASP.NET GridView control. You have a GridView with various TemplateFields, and you are manipulating the columns and visibility of the GridView based on certain conditions in your Page_Load and ImgBtnGo_Click event handlers. You are also dynamically populating a DataTable and binding it to the GridView.
If you have any specific questions or need further assistance with this code, please feel free to ask without requiring translation.
英文:
I've form where I'm using gridview and I'm removing columns at runtime based on some condition and on button click event I'm binding the gridview by populating the datatable but it is showing empty grid with all empty rows only.
Gridview code:
<asp:GridView ID="AccessControlGrid" GridLines="None" CssClass="wk-TableBorder" runat="server"
AutoGenerateColumns = "false" ShowHeaderWhenEmpty="True" EmptyDataText="There are no records.">
<Columns>
<asp:TemplateField HeaderText="User No" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Label ID="lblUserNo" runat="server" Text='<%# Eval("UserNo") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="User Name" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Label ID="lbl_UserName" runat="server" Text='<%# Eval("UserName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Original" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsOriginal" AutoPostback = "True" OnCheckedChanged="Chk_CheckedChanged" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsOriginal")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Continuation" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsContinuation" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsContinuation")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Debtor Amendment" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsDebtorAmendment" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsDebtorAmendment")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Secured Party Amendment" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsSecPartyAmendment" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsSecPartyAmendment")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Partial Assignment" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsPartialAssignment" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsPartialAssignment")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Full Assignment" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsFullAssignment" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsFullAssignment")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Termination" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsTermination" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsTermination")) %>' />
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Submit Collateral Amendment" HeaderStyle-CssClass="SpacerColumn gridheader1 GridColumnSpacing" ItemStyle-CssClass="GridColumnSpacing" HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chk_FS_IsCollateralAmendment" runat="server" Checked='<%# Convert.ToBoolean(Eval("IsCollateralAmendment")) %>' />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
On page load I just have to remove uwanted columns based on some condition and I've to hide the grid:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//This action will be performed once based on access type.
AccessControlGridColumnAdjustment();
AccessControlGrid.Visible = false;
}
}
and finally on button click I've to populate and show grid:
protected void ImgBtnGo_Click(object sender, EventArgs e)
{
if (returnTable == null)
returnTable = new DataTable("AccessControl");
CreateAccessControlDataTable(ref returnTable, hdnAccessType.Value);
LoadData();
PopulateDataTable(ref returnTable, accessControlResultSet, hdnAccessType.Value);
AccessControlGrid.DataSource = returnTable;
AccessControlGrid.DataBind();
AccessControlGrid.Visible = true;
}
Inside CreateAccessControlDataTable I'm just creating the structure of Datatable based on some condition:
public DataTable CreateAccessControlDataTable(ref DataTable returnTable, string accessType)
{
try
{
#region Creating DataTable Schema for different access types
switch (accessType)
{
case "FS":
returnTable.Columns.Add(new DataColumn("UserNo"));
returnTable.Columns.Add(new DataColumn("UserName"));
returnTable.Columns.Add(new DataColumn("IsOriginal"));
returnTable.Columns.Add(new DataColumn("IsContinuation"));
returnTable.Columns.Add(new DataColumn("IsDebtorAmendment"));
returnTable.Columns.Add(new DataColumn("IsSecPartyAmendment"));
returnTable.Columns.Add(new DataColumn("IsPartialAssignment"));
returnTable.Columns.Add(new DataColumn("IsFullAssignment"));
returnTable.Columns.Add(new DataColumn("IsTermination"));
returnTable.Columns.Add(new DataColumn("IsCollateralAmendment"));
break;
case "IPF":
returnTable.Columns.Add(new DataColumn("UserNo"));
returnTable.Columns.Add(new DataColumn("UserName"));
returnTable.Columns.Add(new DataColumn("IsInPrepFilingDeletion"));
break;
case "FLD":
returnTable.Columns.Add(new DataColumn("UserNo"));
returnTable.Columns.Add(new DataColumn("UserName"));
returnTable.Columns.Add(new DataColumn("FloodStopAccess"));
returnTable.Columns.Add(new DataColumn("FloodReIssueAccess"));
returnTable.Columns.Add(new DataColumn("FloodLifeOfLoan"));
returnTable.Columns.Add(new DataColumn("FloodBasicCertificate"));
break;
}
#endregion
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
return returnTable;
}
Inside LoadData() and PopulateDataTable() function I'm just populating the empty Datatable with values from backend that is working fine but at the end I'm getting empty grid with multiple empty rows as below:
I've checked multiple threads here but nothing worked in my case.
> Note: If I do the same thing inside- if (!IsPostback) {} then
> gridview loads properly but I don't have to do that, I've to load the
> grid based on search criteria at postback.
答案1
得分: 1
由于我们使用了模板列(而不是自动生成列),因此我们需要处理“要隐藏的列”。
这也意味着至少对于那些我们隐藏的列,我们不能在标记中真正使用绑定表达式,因为给定的数据源将不包含这些列,绑定将失败。
因此,这表明我们希望控制那些隐藏/显示列的绑定,以及在 GridView 中的隐藏/移除。
我还发现,一旦我们开始做这些事情,一旦我们有很多模板控件,那么我建议在 GridView 的位置使用 ListView(有很多原因,其中一个原因是标记变得不那么“混乱”,因为每个控件(标准 asp.net 控件)都不需要一个模板化的标记部分,此外,您需要一个“项模板”(这会变得太混乱!)。
但是,让我们暂时搁置这些原因,继续使用 GridView。
所以,使用 GridView,这有点复杂,但似乎是最可行的方法之一。
注意:标记中的任何可选列都没有数据绑定表达式(如果数据列缺失,它们将失败)。
因此,这个标记:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" Width="40%" GridLines="None"
CssClass="table table-hover table-striped" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="First">
<ItemTemplate>
<asp:Label ID="lblFirst" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last">
<ItemTemplate>
<asp:Label ID="lblLast" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:Label ID="lblCity" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Hotel Name">
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server"
Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Description">
<ItemTemplate>
<asp:Label ID="lblDesc" runat="server"
Text='<%# Eval("Description") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
以及这段代码来加载数据:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
string strSQL = @"SELECT ID, FirstName, LastName, City, HotelName, Description
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
以及寻找可选字段的行数据绑定:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// 所有“可选”列都在这里
List<string> sOptional =
new List<string> { "FirstName:lblFirst:0", "LastName:lblLast:1", "City:lblCity:2" };
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gBindData = (DataRowView)e.Row.DataItem;
foreach (string sHide in sOptional)
{
string sField = sHide.Split(':')[0];
string sCtrl = sHide.Split(':')[1];
int gCol = Convert.ToInt32(sHide.Split(':')[2]);
if (gBindData.Row.Table.Columns.Contains(sField))
{
Label lbl = (Label)e.Row.FindControl(sCtrl);
lbl.Text = gBindData["FirstName"].ToString();
}
else
{
GridView1.Columns[gCol].Visible = false;
}
}
}
}
因此,我们定义了可选列。我们不使用数据绑定表达式来绑定可选列(如上所示,我们使用代码绑定它们)。上述代码的效果如下图所示:
然而,上述按钮单击包含以下代码:
protected void cmdTest_Click(object sender, EventArgs e)
{
string strSQL = @"SELECT ID, HotelName, Description
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
因此,我们在数据源中省略了3个可选列。
结果如下图所示:
因此,根据上述设计,我们只需从数据源中省略不想要的列,剩下的代码应该正常工作。
编辑:不在第一页加载 GV
为了更完整,我们有以下代码:
注意:对行数据绑定进行了小的编辑(当我们重新绑定 gv 时,必须重新启用(visible = true))。
假设现在我们从开始拥有这个标记:
<asp:Button ID="cmdTest" runat="server" Text="Load data"
CssClass="btn"
OnClick="cmdTest_Click"
/>
<asp:Button ID="cmdTest2" runat="server" Text="Load Different data"
style="margin-left:20px"
CssClass="btn"
OnClick="cmdTest2_Click"
/>
<br />
gv 标记未更改。
现在,代码几乎相同,如下所示:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void cmdTest_Click(object sender, EventArgs e)
{
LoadGrid();
}
protected void cmdTest2_Click(object sender, EventArgs e)
{
string strSQL = @"SELECT ID, HotelName, Description
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1
<details>
<summary>英文:</summary>
Since we using templated columns (not auto generate). Then we need to deal with the columns we "are to hide".
This ALSO suggests that for at least those columns we hide, we can't really use binding expressions in the markup, since the given data source will not have those columns, and they will fail upon binding.
So, this suggests that we want to control the binding of those hide/show columns, and that of hiding/removing from the GV.
I also find that the instant we start to do such things, and the instant we have a LOT of templated controls, then I suggest using a listview in place of gridview. (There are a lot of reasons for this, one grid view simple reason is that the markup becomes less "cluttered" up since each control (standard asp.net controls) do not require a templated markup section, and then on top of that, you need an "item template" (this gets too messy too fast!).
However, let's put aside these reasons, and stick with the gv.
So, with a gridview, this is a bit of a bear to ride and tame, but this seems to be about the most workable.
Note: any optional column in the markup does not have a data binding expression (which would fail if data column is missing).
So, this markup:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ID" Width="40%" GridLines="None"
CssClass="table table-hover table-striped" OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField HeaderText="First">
<ItemTemplate>
<asp:Label ID="lblFirst" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Last">
<ItemTemplate>
<asp:Label ID="lblLast" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="City">
<ItemTemplate>
<asp:Label ID="lblCity" runat="server"></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Hotel Name">
<ItemTemplate>
<asp:Label ID="lblHotel" runat="server"
Text='<%# Eval("HotelName") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
<asp:TemplateField HeaderText="Description">
<ItemTemplate>
<asp:Label ID="lblDesc" runat="server"
Text='<%# Eval("Description") %>'></asp:Label>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
And this code to load:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
LoadGrid();
}
void LoadGrid()
{
string strSQL = @"SELECT ID, FirstName, LastName, City, HotelName, Description
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
And our row data bind that looks for optional fields.
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// all columns that are "optional" go here
List<string> sOptional =
new List<string> { "FirstName:lblFirst:0", "LastName:lblLast:1", "City:lblCity:2" };
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gBindData = (DataRowView)e.Row.DataItem;
foreach (string sHide in sOptional)
{
string sField = sHide.Split(':')[0];
string sCtrl = sHide.Split(':')[1];
int gCol = Convert.ToInt32(sHide.Split(':')[2]);
if (gBindData.Row.Table.Columns.Contains(sField))
{
Label lbl = (Label)e.Row.FindControl(sCtrl);
lbl.Text = gBindData["FirstName"].ToString();
}
else
{
GridView1.Columns[gCol].Visible = false;
}
}
}
}
So, we define the optional columns. We do not use data bind expressions for optional columns (we bind them with code as per above. The above displays like this:
[![enter image description here][1]][1]
However, the above button click has this code:
protected void cmdTest_Click(object sender, EventArgs e)
{
string strSQL = @"SELECT ID, HotelName, Description
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
So, we left out of the data source the 3 optional columns.
The result is thus this:
[![enter image description here][2]][2]
So, with the above design, we just leave out the columns we don't want from the data source, and the rest of the code should just work.
Edit: Not loading GV on first page load
=======
To be more complete here, we have this code:
NB: a small edit was made to the row data bound (we have to re-enable (visible = true) for when we re-bind the gv.
So, say we now have this markup at start:
<asp:Button ID="cmdTest" runat="server" Text="Load data"
CssClass="btn"
OnClick="cmdTest_Click"
/>
<asp:Button ID="cmdTest2" runat="server" Text="Load Different data"
style="margin-left:20px"
CssClass="btn"
OnClick="cmdTest2_Click"
/>
<br />
gv markup is un-changed.
And now the code is really much the same, and is this:
protected void Page_Load(object sender, EventArgs e)
{
}
protected void cmdTest_Click(object sender, EventArgs e)
{
LoadGrid();
}
protected void cmdTest2_Click(object sender, EventArgs e)
{
string strSQL = @"SELECT ID, HotelName, Description
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
void LoadGrid()
{
string strSQL = @"SELECT ID, FirstName, LastName, City, HotelName, Description
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
// all columns that are "optional" go here
List<string> sOptional =
new List<string> { "FirstName:lblFirst:0", "LastName:lblLast:1", "City:lblCity:2" };
if (e.Row.RowType == DataControlRowType.DataRow)
{
DataRowView gBindData = (DataRowView)e.Row.DataItem;
foreach (string sHide in sOptional)
{
string sField = sHide.Split(':')[0];
string sCtrl = sHide.Split(':')[1];
int gCol = Convert.ToInt32(sHide.Split(':')[2]);
if (gBindData.Row.Table.Columns.Contains(sField))
{
Label lbl = (Label)e.Row.FindControl(sCtrl);
lbl.Text = gBindData["FirstName"].ToString();
GridView1.Columns[gCol].Visible = true;
}
else
{
GridView1.Columns[gCol].Visible = false;
}
}
}
}
And result is now this:
[![enter image description here][3]][3]
Note closely: the hide or show of columns will persist even when you do a full-rebind of the gv. (since your columns are tempalted).
This means if you hide a column (due to one data source bind), then those columns WILL retain their setting when you re-bind!
Solution: Your code that hides columns must also un-hide the columns!
So, this issue has nothing to do with the gv being loaded on page load or not. The issue of course is that if you bind the gv, hide some columns, and re-bind? Those columns will remain hidden, and they do not re-set their visible sitting on a re-bind.
Edit 2: Get selected rows by user
=====
Assume a check box in the grid. It can be bound to data, or not, does not matter.
So, add this markup to the gv.
<asp:TemplateField HeaderText="Active" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:CheckBox ID="chkActive" runat="server"
checked='<%# Eval("Active") %>'
/>
</ItemTemplate>
</asp:TemplateField>
And our data sources now include column Active:
eg this:
protected void cmdTest_Click(object sender, EventArgs e)
{
LoadGrid();
}
protected void cmdTest2_Click(object sender, EventArgs e)
{
string strSQL = @"SELECT ID, HotelName, Description, Active
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
void LoadGrid()
{
string strSQL = @"SELECT ID, FirstName, LastName, City, HotelName, Description, Active
FROM tblHotelsA
ORDER BY HotelName";
GridView1.DataSource = General.MyRst(strSQL);
GridView1.DataBind();
}
And right after the gv, say we have this:
<asp:Button ID="cmdShowChecked" runat="server" Text="Get Selected"
style="margin-left:20px"
CssClass="btn"
OnClick="cmdShowChecked_Click"
/>
<asp:Label ID="lblSelected" runat="server" Text=""
style="margin-left:30px">
</asp:Label>
So, result is now this:
[![enter image description here][4]][4]
Code for selected button click after gv is this:
protected void cmdShowChecked_Click(object sender, EventArgs e)
{
string sPKIDSelected = "";
foreach (GridViewRow gRow in GridView1.Rows)
{
string sPK = GridView1.DataKeys[gRow.RowIndex]["ID"].ToString();
CheckBox chkSel = (CheckBox)gRow.FindControl("chkActive");
if (chkSel.Checked)
{
if (sPKIDSelected != "")
sPKIDSelected += ",";
sPKIDSelected += sPK;
}
}
string strSQL = $@"SELECT * FROM tblHotelsA
WHERE ID IN ({sPKIDSelected})
ORDER BY HotelName";
DataTable MySelected = General.MyRst(strSQL);
lblSelected.Text =
$"PK database ID selected = {sPKIDSelected} Rows Selected = {MySelected.Rows.Count}";
// do whatever with selected data table items
}
[1]: https://i.stack.imgur.com/MIYMv.png
[2]: https://i.stack.imgur.com/aBnzH.png
[3]: https://i.stack.imgur.com/sUyIj.gif
[4]: https://i.stack.imgur.com/iv0ON.gif
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论