为转发器中的文本框创建动态 ID
Creating dynamic id for textbox in repeater
所以我从 DB 获取信息并在 ASP 转发器中使用它来获取 table。
<asp:Repeater ID="repS" runat="server">
<ItemTemplate>
<a class="card-title text-secondary" href="#">
<%#Eval("FirstName") %>
<%#Eval("LastName") %>
(<%#Eval("Id")%>)
</a>
<asp:DropDownList ID="reasonStd<%#Eval("Id")%>" runat="server">
<asp:ListItem Enabled="true" Text="Select Month" Value="-1"></asp:ListItem>
<asp:ListItem Text="1" Value="1"></asp:ListItem>
<asp:ListItem Text="2" Value="2"></asp:ListItem>
<asp:ListItem Text="3" Value="3"></asp:ListItem>
...
</asp:DropDownList>
<span>
最多可以有10个选项。现在我想选择一个选项 (id=reasonStd) 并使用一个按钮将每个选项保存在数据库中,但我不知道如何获取转发器中每个项目的每个 id。
当我检查代码时,我可以看到下拉列表在前端创建得很好(reasonStd1248、reasonStd2371),但找不到调用它并将其保存到数据库的方法(我已经有了方法测试和 运行)。我试过类似...
foreach (objetType obj in DataSource)
{
saveObject(obj, reasonStd+obj.Id+.Text.SelectedValue);
}
好吧,问题是空值扭曲了事情。
(我同意这是一个问题+挑战)。
因此,推回值 - 通常不是问题。无论是文本框、复选框等 - 然后再没有真正的问题。
但是,组合框有两个问题。通常我们提供给它的列表没有空白(别无选择),更糟糕的是我们不能从数据库中提供一个空值加倍糟糕!!!
现在您的下拉列表(组合)充满了静态列表。但它可以很好地填充数据 table。我将 post 一个使用数据 table 驱动我们的“项目”(中继器)的示例,然后还包含一个下拉列表,该列表也来自 table 个选择。
所以,假设标记是这样的:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<div style="border-style:solid;color:black;width:250px;float:left">
<div style="padding:5px;text-align:right">
Hotel Name: <asp:TextBox ID="txtHotelName" runat="server" Text ='<%# Eval("HotelName") %>' Width="130px" />
<br />
First Name: <asp:TextBox ID="txtFirst" runat="server" Text ='<%# Eval("FirstName") %>' Width="130px" />
<br />
Last Name: <asp:TextBox ID="txtLast" runat="server" Text ='<%# Eval("LastName") %>' Width="130px" />
<br />
City : <asp:DropDownList ID="cboCity" runat="server" DataTextField="City"
DataValueField="City" Width="130px">
</asp:DropDownList>
<br />
Active: <asp:CheckBox ID="chkActive" runat="server" Checked = '<%# Eval("Active") %>'/>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
因此,在上面,我们有一些文本框、一个下拉列表和一个复选框。
您可以看到我们用 Eval() 填充了这些控件。
因此,填充中继器的代码如下所示:
public void LoadGrid()
{
// load up our drop down list from database
string strSQL;
strSQL = "SELECT City from tblCity Order by City";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
rstCity.Load(cmdSQL.ExecuteReader);
}
// now load up our repeter
strSQL = "SELECT ID, FirstName, LastName, HotelName, City, Active from tblHotels ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
rstTable.Load(cmdSQL.ExecuteReader);
Repeater1.DataSource = rstTable;
Repeater1.DataBind();
}
}
好的,上面的现在可以工作了。您会非常小心地注意到,我在 class 级别删除了 rstHotels 数据 table,因为我们稍后需要它。在我的例子中,因为我的下拉列表没有像你的那样的 static/fixed 来源,所以上面也会加载它。
结果是这样的:
您会在上面注意到,我们有一个保存按钮。保存按钮代码是这样做的:
将数据从中继器发送回填满中继器的相同 table。 (是的,我们确实坚持 table in Session().
所以,代码真的很简单 - 而且代码不多:
protected void cmdSave_Click(object sender, EventArgs e)
{
// pull repeater rows back to table.
foreach (RepeaterItem rRow in Repeater1.Items)
{
int RecordPtr = rRow.ItemIndex;
DataRow OneDataRow;
OneDataRow = rstTable.Rows(RecordPtr);
OneDataRow.Item("HotelName") = rRow.FindControl("txtHotelName") as TextBox.Text;
OneDataRow.Item("FirstName") = rRow.FindControl("txtFirst") as TextBox.Text;
OneDataRow.Item("LastName") = rRow.FindControl("txtLast") as TextBox.Text;
OneDataRow.Item("City") = rRow.FindControl("cboCity") as DropDownList.Text;
OneDataRow.Item("Active") = rRow.FindControl("chkActive") as CheckBox.Checked;
}
// now send table back to database with updates
string strSQL = "SELECT ID, FirstName, LastName, City, HotelName, Active from tblHotels WHERE ID = 0";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);
daupdate.Update(rstTable);
}
}
还有一个供参考:gridview、listview 和可能还有十几个控件?如果您不参加或没有替代模板,那么您不必担心也不必打扰。转发器控制是其中的一个例外。 (按照上面的规定,您必须测试项目行和替代行 - 我不知道为什么 - 但您必须这样做 - 不要离开该替代行)。
好的,以上所做的就是循环转发器,并将值发送回 table。然后我们获取 table,并执行单个 .update 命令。
所以,现在唯一真正的问题是处理空下拉列表。
您在 itemdata 绑定事件中处理该问题。像这样说:
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// set combo box data source
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{
// setup drop down list
//
int ix = e.Item.ItemIndex;
DropDownList cboDrop = e.Item.FindControl("cboCity");
cboDrop.DataSource = rstCity;
cboDrop.DataBind();
cboDrop.Items.Insert(0, new ListItem(string.Empty)); // add blank row
if (IsDBNull(rstTable.Rows(ix).Item("City")) == false)
cboDrop.Text = rstTable.Rows(ix).Item("City");
else
cboDrop.Text = "";
}
}
现在在您的代码中?您可以跳过填充 + 数据绑定,但请注意最后一点 - test/check 表示空值。还要注意我是如何在下拉列表中添加额外的 BLANK selection 的。您需要空白的额外选择,因为许多数据行可能还没有 selected 值。而且你不能推入 null,也不能推入一个空字符串,直到允许空白空字符串选项被添加到下拉列表中。现在在你的情况下,因为它是硬代码 - 那么你可以在你的标记中添加额外的空白选择 - 我不能,因为我的下拉列表是数据库驱动的。
如前所述,我确实保留了导致整个混乱的数据 table,我这样做是为了轻松发送回数据库。您可以重新拉取或创建一个空白数据table (select id = 0,然后添加行,但鉴于数据集只有大约 20-40 个项目,然后持久化数据table 对 session() 系统的压力不大。
因此,第一页 post- 后台加载如下所示:
private DataTable rstTable = new DataTable();
private DataTable rstCity = new DataTable();
protected void Page_Load(object sender, System.EventArgs e)
{
if (System.Web.UI.Page.IsPostBack == false)
{
LoadGrid();
System.Web.UI.Page.Session["MyTable"] = rstTable;
System.Web.UI.Page.Session["MyCity"] = rstCity;
}
else
{
rstTable = System.Web.UI.Page.Session["MyTable"];
rstCity = System.Web.UI.Page.Session["MyCity"];
}
}
}
以上是我如何保留 table,以及我们的下拉列表的 tblCity(您没有)。
因此,您必须在 itemdata 绑定上捕获 + 设置下拉列表。如果您在标记中只是设置下拉列表
,您可能不必这样做
例如:
Text = '<%# Eval("City") %>'
但是,以上对我来说失败了,因为有些列还没有值,当您尝试 set/use 不存在的值时,组合框变得相当 mad/nasty .并在上面扔空值 - 它变得更糟。因此,我在 itemdatabound 中必须为每个“重复”项目填写下拉列表,因此我还必须将空白行选项添加到下拉列表中。然后我检查是否为 null,并插入空白(空字符串)或值。
请注意,如果仔细观察,上述 posted 代码将因此导致文本框和值为 null 的空字符串。您可以自由地将数据行中的 null.Item() 分配给文本框,但不能将下拉列表中的文本设置为空 - 因此我们使用 itematabound 来设置我们的下拉列表。
理论上,更新代码应该 test/check 用于空字符串,如果这是您当前的约定,则将“null”保存回数据库。 (即:没有空值和空字符串,或者空值和没有空字符串)。所以,无论你现在有什么约定,都应该坚持。
如前所述,您不必在 itemdata 绑定中填充下拉列表,但您必须处理空值检查 - 如前所述,添加额外下拉选项(空白)的代码可能也可以被您跳过,并简单地添加到您的硬编码选择列表中。但是您仍然必须处理 null - 我在上面只是检查了一个空行值,并推入一个空字符串以使它起作用。
所以我从 DB 获取信息并在 ASP 转发器中使用它来获取 table。
<asp:Repeater ID="repS" runat="server">
<ItemTemplate>
<a class="card-title text-secondary" href="#">
<%#Eval("FirstName") %>
<%#Eval("LastName") %>
(<%#Eval("Id")%>)
</a>
<asp:DropDownList ID="reasonStd<%#Eval("Id")%>" runat="server">
<asp:ListItem Enabled="true" Text="Select Month" Value="-1"></asp:ListItem>
<asp:ListItem Text="1" Value="1"></asp:ListItem>
<asp:ListItem Text="2" Value="2"></asp:ListItem>
<asp:ListItem Text="3" Value="3"></asp:ListItem>
...
</asp:DropDownList>
<span>
最多可以有10个选项。现在我想选择一个选项 (id=reasonStd) 并使用一个按钮将每个选项保存在数据库中,但我不知道如何获取转发器中每个项目的每个 id。
当我检查代码时,我可以看到下拉列表在前端创建得很好(reasonStd1248、reasonStd2371),但找不到调用它并将其保存到数据库的方法(我已经有了方法测试和 运行)。我试过类似...
foreach (objetType obj in DataSource)
{
saveObject(obj, reasonStd+obj.Id+.Text.SelectedValue);
}
好吧,问题是空值扭曲了事情。
(我同意这是一个问题+挑战)。
因此,推回值 - 通常不是问题。无论是文本框、复选框等 - 然后再没有真正的问题。
但是,组合框有两个问题。通常我们提供给它的列表没有空白(别无选择),更糟糕的是我们不能从数据库中提供一个空值加倍糟糕!!!
现在您的下拉列表(组合)充满了静态列表。但它可以很好地填充数据 table。我将 post 一个使用数据 table 驱动我们的“项目”(中继器)的示例,然后还包含一个下拉列表,该列表也来自 table 个选择。
所以,假设标记是这样的:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<div style="border-style:solid;color:black;width:250px;float:left">
<div style="padding:5px;text-align:right">
Hotel Name: <asp:TextBox ID="txtHotelName" runat="server" Text ='<%# Eval("HotelName") %>' Width="130px" />
<br />
First Name: <asp:TextBox ID="txtFirst" runat="server" Text ='<%# Eval("FirstName") %>' Width="130px" />
<br />
Last Name: <asp:TextBox ID="txtLast" runat="server" Text ='<%# Eval("LastName") %>' Width="130px" />
<br />
City : <asp:DropDownList ID="cboCity" runat="server" DataTextField="City"
DataValueField="City" Width="130px">
</asp:DropDownList>
<br />
Active: <asp:CheckBox ID="chkActive" runat="server" Checked = '<%# Eval("Active") %>'/>
</div>
</div>
</ItemTemplate>
</asp:Repeater>
因此,在上面,我们有一些文本框、一个下拉列表和一个复选框。
您可以看到我们用 Eval() 填充了这些控件。
因此,填充中继器的代码如下所示:
public void LoadGrid()
{
// load up our drop down list from database
string strSQL;
strSQL = "SELECT City from tblCity Order by City";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
rstCity.Load(cmdSQL.ExecuteReader);
}
// now load up our repeter
strSQL = "SELECT ID, FirstName, LastName, HotelName, City, Active from tblHotels ORDER BY HotelName";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
rstTable.Load(cmdSQL.ExecuteReader);
Repeater1.DataSource = rstTable;
Repeater1.DataBind();
}
}
好的,上面的现在可以工作了。您会非常小心地注意到,我在 class 级别删除了 rstHotels 数据 table,因为我们稍后需要它。在我的例子中,因为我的下拉列表没有像你的那样的 static/fixed 来源,所以上面也会加载它。
结果是这样的:
您会在上面注意到,我们有一个保存按钮。保存按钮代码是这样做的:
将数据从中继器发送回填满中继器的相同 table。 (是的,我们确实坚持 table in Session().
所以,代码真的很简单 - 而且代码不多:
protected void cmdSave_Click(object sender, EventArgs e)
{
// pull repeater rows back to table.
foreach (RepeaterItem rRow in Repeater1.Items)
{
int RecordPtr = rRow.ItemIndex;
DataRow OneDataRow;
OneDataRow = rstTable.Rows(RecordPtr);
OneDataRow.Item("HotelName") = rRow.FindControl("txtHotelName") as TextBox.Text;
OneDataRow.Item("FirstName") = rRow.FindControl("txtFirst") as TextBox.Text;
OneDataRow.Item("LastName") = rRow.FindControl("txtLast") as TextBox.Text;
OneDataRow.Item("City") = rRow.FindControl("cboCity") as DropDownList.Text;
OneDataRow.Item("Active") = rRow.FindControl("chkActive") as CheckBox.Checked;
}
// now send table back to database with updates
string strSQL = "SELECT ID, FirstName, LastName, City, HotelName, Active from tblHotels WHERE ID = 0";
using (SqlCommand cmdSQL = new SqlCommand(strSQL, new SqlConnection(My.Settings.TEST3)))
{
cmdSQL.Connection.Open();
SqlDataAdapter daupdate = new SqlDataAdapter(cmdSQL);
SqlCommandBuilder cmdBuild = new SqlCommandBuilder(daupdate);
daupdate.Update(rstTable);
}
}
还有一个供参考:gridview、listview 和可能还有十几个控件?如果您不参加或没有替代模板,那么您不必担心也不必打扰。转发器控制是其中的一个例外。 (按照上面的规定,您必须测试项目行和替代行 - 我不知道为什么 - 但您必须这样做 - 不要离开该替代行)。
好的,以上所做的就是循环转发器,并将值发送回 table。然后我们获取 table,并执行单个 .update 命令。
所以,现在唯一真正的问题是处理空下拉列表。
您在 itemdata 绑定事件中处理该问题。像这样说:
protected void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
// set combo box data source
if (e.Item.ItemType == ListItemType.Item | e.Item.ItemType == ListItemType.AlternatingItem)
{
// setup drop down list
//
int ix = e.Item.ItemIndex;
DropDownList cboDrop = e.Item.FindControl("cboCity");
cboDrop.DataSource = rstCity;
cboDrop.DataBind();
cboDrop.Items.Insert(0, new ListItem(string.Empty)); // add blank row
if (IsDBNull(rstTable.Rows(ix).Item("City")) == false)
cboDrop.Text = rstTable.Rows(ix).Item("City");
else
cboDrop.Text = "";
}
}
现在在您的代码中?您可以跳过填充 + 数据绑定,但请注意最后一点 - test/check 表示空值。还要注意我是如何在下拉列表中添加额外的 BLANK selection 的。您需要空白的额外选择,因为许多数据行可能还没有 selected 值。而且你不能推入 null,也不能推入一个空字符串,直到允许空白空字符串选项被添加到下拉列表中。现在在你的情况下,因为它是硬代码 - 那么你可以在你的标记中添加额外的空白选择 - 我不能,因为我的下拉列表是数据库驱动的。
如前所述,我确实保留了导致整个混乱的数据 table,我这样做是为了轻松发送回数据库。您可以重新拉取或创建一个空白数据table (select id = 0,然后添加行,但鉴于数据集只有大约 20-40 个项目,然后持久化数据table 对 session() 系统的压力不大。
因此,第一页 post- 后台加载如下所示:
private DataTable rstTable = new DataTable();
private DataTable rstCity = new DataTable();
protected void Page_Load(object sender, System.EventArgs e)
{
if (System.Web.UI.Page.IsPostBack == false)
{
LoadGrid();
System.Web.UI.Page.Session["MyTable"] = rstTable;
System.Web.UI.Page.Session["MyCity"] = rstCity;
}
else
{
rstTable = System.Web.UI.Page.Session["MyTable"];
rstCity = System.Web.UI.Page.Session["MyCity"];
}
}
}
以上是我如何保留 table,以及我们的下拉列表的 tblCity(您没有)。
因此,您必须在 itemdata 绑定上捕获 + 设置下拉列表。如果您在标记中只是设置下拉列表
,您可能不必这样做例如:
Text = '<%# Eval("City") %>'
但是,以上对我来说失败了,因为有些列还没有值,当您尝试 set/use 不存在的值时,组合框变得相当 mad/nasty .并在上面扔空值 - 它变得更糟。因此,我在 itemdatabound 中必须为每个“重复”项目填写下拉列表,因此我还必须将空白行选项添加到下拉列表中。然后我检查是否为 null,并插入空白(空字符串)或值。
请注意,如果仔细观察,上述 posted 代码将因此导致文本框和值为 null 的空字符串。您可以自由地将数据行中的 null.Item() 分配给文本框,但不能将下拉列表中的文本设置为空 - 因此我们使用 itematabound 来设置我们的下拉列表。
理论上,更新代码应该 test/check 用于空字符串,如果这是您当前的约定,则将“null”保存回数据库。 (即:没有空值和空字符串,或者空值和没有空字符串)。所以,无论你现在有什么约定,都应该坚持。
如前所述,您不必在 itemdata 绑定中填充下拉列表,但您必须处理空值检查 - 如前所述,添加额外下拉选项(空白)的代码可能也可以被您跳过,并简单地添加到您的硬编码选择列表中。但是您仍然必须处理 null - 我在上面只是检查了一个空行值,并推入一个空字符串以使它起作用。