0

我有一个中继器用 1 个文本和多个填充表行,HtmlRadioButtons用户应该检查。因为列表可能会变得非常大,所以只检查前 N 行是强制性的。为了向用户展示这一点,我在第一个可选行之前添加了一个额外TableRow的(colspan=4) 和一些说明性文本。TableCell我在中继器上添加了这一行ItemDataBound

在回发时,额外行之前和之后的所有选中单选按钮都会返回它们的选中值,除了我在之前插入额外行的一项。我尝试改变额外行(和)的类型,并尝试改变Html/RadioButton额外行。但是我不能让这个行/单选按钮回发检查值,它总是错误的。Html/TableRowHtml/TableCellEnableViewState

有谁知道为什么这个值不回发?
有人知道如何在不阻止单选按钮回发的情况下添加额外的行吗?

额外说明:

  • 我不想向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>

添加行后面的代码(受此 Experts-Exchange-post Repeater Control 启发 - 添加另一个表行

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 背后的代码(灵感来自系统博客的这个 Chief of the System Blog 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;
}
4

1 回答 1

1

尽管您的一般方法是正确的,但 IMO 似乎您将整个事情复杂化了。

  1. 您不需要服务器端表格控件,即:<asp:TableRow runat="server">. 通过使用服务器控件而不是 html 控件,您极大地夸大了您的 ViewState。请记住,为了恢复 PostBack 上的转发器,.NET 需要在一个隐藏字段中维护所有服务器控件,该隐藏字段存储在您要返回给客户端的页面中。简单的 html 标记,即:<td>,在这里就足够了。
  2. 无需在代码隐藏中添加新行,您只需将 Panel 控件的可见性设置为 false。绑定中继器时,您可以将面板的可见性设置为需要它的行的 true。

如果您需要上述任何代码,请问,我很乐意提供一些。

另外,您的问题还不清楚,但是您是否只有一个要显示的文本值(CategoryName)?如果是这样,您可以从转发器中删除这部分,并且只在单选按钮上进行迭代。

你为什么使用单选按钮。同样,您的问题并不清楚,但您声明:在 extra row 之前和之后所有选中的单选按钮。这似乎暗示用户可以选择多个单选按钮。单选按钮的正确用法是您希望用户只选择一项。在我看来,复选框列表将是此处使用的正确控件。

就您遇到的问题而言,很可能是因为您没有在回发时恢复动态添加的表行,这会破坏 ViewState 的恢复。请记住,为了正确恢复 ViewState,在恢复 ViewState时必须存在确切数量的控件。如果您按照我使用更新面板的示例进行操作,这应该可以缓解问题。

编辑

要了解为什么添加不可见的服务器控件有效而在代码中添加新控件无效,您需要了解 Viewstate 的工作原理。可以在这里找到全面的解释了解 ASP.NET 视图状态。但简而言之,因为,正如我之前所说:当 ViewState 恢复时,必须存在确切数量的控件,当您的服务器控件的可见性设置为 false 时,它​​们确实存在于页面回发并且 ViewState 为恢复。当您通过代码添加它们时,您必须明确地重新添加它们。我希望这个解释是有道理的。

代码示例:

<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>

高温高压

于 2013-02-12T14:27:22.977 回答