我有一个转发器填充表格 - 行有1个文本和多个HtmlRadioButtons
,用户应该检查。
因为列表可能变得非常大,所以只检查前N行是必须的。
为了向用户显示这一点,我在第一个可选行之前添加了一个TableRow
,其中一个TableCell
(colspan = 4)带有一些指令文本。
我在转发器ItemDataBound
上添加了这一行。
在回发后,所有选中的单选按钮执行之前和之后的所有选中的单选按钮都会返回其选中的值,除了之前我插入额外行的一项。
我尝试改变额外行(Html/RadioButton
,Html/TableRow
和Html/TableCell
)的类型,并尝试在额外行上改变EnableViewState
。
但是我无法通过此行/单选按钮回发已检查的值,它始终为false。
有人知道为什么这个值没有回发吗? 有没有人知道如何在不阻止单选按钮回发的情况下添加额外的行?
额外备注:
OnClick
,因为我喜欢一次处理和存储所有值Page_Load
下载原始数据,但这对其他行/ RadioButtons来说似乎不是问题这是简化的精简代码。 ASPX:
<ItemTemplate>
<asp:TableRow runat="server">
<asp:TableCell ID="CategoryName" CssClass="td_1" Text='<%# Eval("Name") %>'/>
<asp:TableCell CssClass="td_radio" runat="server">
<asp:HtmlInputRadioButton type="radio" runat="server"
ID="rdBelonging"
Name='<%# Eval("Id") %>'
value='<%# (int)Enum_BelongsToCategory.Belonging %>'
data-value='<%# Convert.ToBoolean(Eval("ShouldJudge")) ? "mandatory" : "optional" %>'/>
</asp:TableCell>
<asp:TableCell CssClass="td_radio" runat="server">
<asp:HtmlInputRadioButton type="radio" runat="server"
ID="rdNotBelonging"
Name='<%# Eval("Id") %>'
value='<%# (int)Enum_BelongsToCategory.NotBelonging %>'
data-value='<%# Convert.ToBoolean(Eval("ShouldJudge")) ? "mandatory" : "optional" %>'/>
</asp:TableCell>
<%-- more Enum_BelongsToCategory-ReadioButtons... --%>
</asp:TableRow>
</ItemTemplate>
添加该行的代码(受此专家交流帖Repeater Control -- Adding another table row的启发:
protected void repeater_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
// first get item and show previous checks (if any)
// ...
if ( (lDataItem.ShouldJudge == false) && (_prevShouldJudge) ) {
var lCell = new TableCell { ColSpan = 4, InnerText = "(minimum to check)" };
var lRow = new TableRow();
lRow.Cells.Add(lCell);
e.Item.Controls.AddAt(0, lRow);
}
_prevShouldJudge = lDataItem.ShouldJudge;
}
}
查找已检查的RadioButton背后的代码(受此系统博客主管的启发find checked radio-button in aspnet)
private void SaveCategoryJudgements(Product product)
{
int lRepeaterItemCount = 0;
foreach (RepeaterItem lItem in repeaterCategories.Items) {
lRepeaterItemCount ++;
var lCheckedRadioButton = GetCheckedRadioButton(lItem.Controls);
if (lCheckedRadioButton != null) {
int lCategoryId;
int lJudgement;
if ( (int.TryParse(lCheckedRadioButton.Attributes["value"], out lJudgement))
&& (int.TryParse(lCheckedRadioButton.Name, out lCategoryId)) )
{
ClassificationData.SaveDocumentCategoryByUser(product, lCategoryId, (Enum_BelongsToCategory)lJudgement);
}
}
}
}
public HtmlInputRadioButton GetCheckedRadioButton(ControlCollection controls)
{
foreach (Control lControl in controls) {
if (lControl is HtmlInputRadioButton) {
var lRadioButton = (HtmlInputRadioButton)lControl;
if (lRadioButton.Checked == true)
{
return lRadioButton;
}
}
else {
var lRadioButton = GetCheckedRadioButton(lControl.Controls);
if (lRadioButton != null) {
return lRadioButton;
}
}
}
return null;
}
答案 0 :(得分:1)
虽然你的一般方法是正确的,但IMO似乎让你的整个事情变得复杂。
<asp:TableRow runat="server">
。通过使用服务器控件而不是html控件,您非常过度膨胀ViewState。请记住,为了在PostBack上恢复转发器,.NET需要在隐藏字段中维护所有服务器控件,该字段存储在您要服务回客户端的页面中。简单的html标记,即:<td>
,就足够了。如果你需要上述任何代码,请问,我很乐意提供一些。
此外,您的问题并不清楚,但是您只显示一个文本值(CategoryName)吗?如果是这样,您可以从转发器中删除此部分,并仅迭代单选按钮。
为什么使用单选按钮?同样,您的问题并不清楚,但您说明:在额外行之前和之后所有选中的单选按钮。这似乎意味着用户可以选择多个单选按钮。如果您希望用户仅选择一个项,则单选按钮的正确用法。在我看来,复选框列表将是在这里使用的正确控件。
就你遇到的问题而言,最有可能的原因是你没有在回发时恢复动态添加的表格,这会搞乱ViewState的恢复。请记住,为了正确恢复ViewState,恢复ViewState时必须存在 确切数字 控件。如果您按照我使用更新面板的示例,这应该可以缓解此问题。
修改强>
要理解添加不可见服务器控件的原因并在代码中添加新控件的原因,您需要了解Viewstate的工作原理。可在此处找到详尽的解释Understanding ASP.NET View State。但简而言之,正如我之前所说的那样:当ViewState恢复时,当您的服务器控件的可见性设置为false时,必须存在 确切数字 控件,当页面回发并恢复ViewState时,它们 做 存在。当您通过代码添加它们时,您必须expolicitly重新添加它们。我希望这种解释是有道理的。
代码示例:
<ItemTemplate>
<tr>
<td>'<%# Eval("Name") %>'</td>
<td><asp:RadioButton ID="rdBelonging" ...</td>
<!-- more Enum_BelongsToCategory-RadioButtons... -->
</tr>
<asp:Panel ID="pnlExplanationRow" runat="server" Visible="false">
<tr>
<td colspan=?>....</td>
</tr>
</asp:Panel>
</ItemTemplate>
HTH