36

我有一个模板化控件(一个中继器),列出了一些文本和其他标记。每个项目都有一个与之关联的单选按钮,使用户可以选择由转发器创建的项目之一。

转发器写入单选按钮,设置其 id 和生成的名称,使用默认的 ASP.NET 命名约定,使每个单选按钮成为一个完整的“组”。这意味着所有单选按钮都是相互独立的,不幸的是,这再次意味着我可以同时选择所有单选按钮。单选按钮具有用于设置通用名称的巧妙属性“组名”,因此它们被组合在一起,因此应该相互依赖(所以我一次只能选择一个)。问题是 - 这不起作用 - 转发器确保 id 和名称(控制分组)是不同的。

由于我使用中继器(可能是列表视图或任何其他模板化数据绑定控件),因此我无法使用 RadioButtonList。那么,这让我何去何从?

我知道我以前遇到过这个问题并解决了它。我知道几乎每个 ASP.NET 程序员都必须拥有它,那么为什么我不能 google 并找到解决问题的可靠方法呢?我遇到了通过 JavaScript 强制分组的解决方案(丑陋!),甚至将单选按钮作为非服务器控件处理,迫使我做一个Request.Form[name]来读取状态。我还尝试尝试覆盖PreRender事件上的名称属性 - 不幸的是,拥有页面和母版页再次覆盖此名称以反映完整的 ID/名称,所以我最终得到了相同的错误结果。

如果您没有比我发布的更好的解决方案,仍然非常欢迎您发表您的想法 - 至少我会知道我的朋友“杰克”是正确的,关于 ASP.NET 有时是多么混乱;)

4

14 回答 14

9

ASP.NET 提示:在中继器中使用 RadioButton 控件

这是 JavaScript 函数的代码:

function SetUniqueRadioButton(nameregex, current)
{
   re = new RegExp(nameregex);
   for(i = 0; i < document.forms[0].elements.length; i++)
   {
      elm = document.forms[0].elements[i]
      if (elm.type == 'radio')
      {
         if (re.test(elm.name))
         {
            elm.checked = false;
         }
      }
   }
   current.checked = true;
}

代码通过ItemDataBound 事件链接到Repeater。要使其正常工作,您需要知道Repeater 控件的名称,以及您分配给RadioButtons 的GroupName。在这种情况下,我使用 rptPortfolios 作为中继器的名称,并使用 Portfolios 作为组名:

protected void rptPortfolios_ItemDataBound(object sender,
                                           RepeaterItemEventArgs e)
{
   if (e.Item.ItemType != ListItemType.Item && e.Item.ItemType
      != ListItemType.AlternatingItem)
      return;

   RadioButton rdo = (RadioButton)e.Item.FindControl("rdoSelected");
   string script =
      "SetUniqueRadioButton('rptPortfolios.*Portfolios',this)";
   rdo.Attributes.Add("onclick", script);

}

参考: http: //www.codeguru.com/csharp/csharp/cs_controls/custom/article.php/c12371/

于 2009-01-01T20:13:03.080 回答
7

Google-fu:asp.net 单选按钮中继器问题

确实是 id 修改的不幸后果。我的想法是创建一个 - 或从众多可用的 - 自定义控件中选择一个,以在客户端上添加对同名的支持。

于 2008-12-18T10:20:31.977 回答
6

Vladimir Smirnov 已经创建了一个很好的自定义控件来解决这个问题。我们一直在我们的项目中使用GroupRadioButton,它与在中继器内部创建的单选按钮以及在中继器外部创建的其他单选按钮都属于同一组的一部分。

于 2009-11-01T23:37:41.167 回答
6

我使用 jQuery 脚本:

<script type="text/javascript">
    function norm_radio_name() {
        $("[type=radio]").each(function (i) {
            var name = $(this).attr("name");
            var splitted = name.split("$");
            $(this).attr("name", splitted[splitted.length - 1]);
        });
    };

    $(document).ready(function () {
        norm_radio_name();
    });

    // for UpdatePannel
    var prm = Sys.WebForms.PageRequestManager.getInstance();

    prm.add_endRequest(function () {
        norm_radio_name();
    });
</script>
于 2010-08-29T10:59:58.400 回答
5

我知道这是一篇旧文章,但这是我最终使用列表视图所做的。我的列表视图绑定在 VB 代码隐藏中,所以我不确定这是否适用于中继器,但我想它可能是相似的。

我所做的是使用取消选择任何其他单选按钮的功能来处理单选按钮的 OnCheckChanged 事件。然后,当我离开页面时,我寻找了选定的单选按钮。

该解决方案避免了 JavaScript 和 jQuery,并且完全忽略了 GroupName 问题。这并不理想,但它的功能与(我)预期的一样。我希望它对其他人有帮助。

标记:

<asp:ListView ID="lvw" runat="server">
  <LayoutTemplate>`
    <table>
      <th>Radio</th>
      <tr id="itemPlaceholder"></tr>
    </table>
  </LayoutTemplate>
  <ItemTemplate>
    <tr>
      <td><asp:RadioButton ID="rdbSelect" runat="server" AutoPostBack="true"
           OnCheckedChanged="rdbSelect_Changed"/></td>
    </tr>
  </ItemTemplate>
</asp:ListView>

代码:

Protected Sub rdbSelect_Changed(ByVal sender As Object, ByVal e As System.EventArgs)

  Dim rb1 As RadioButton = CType(sender, RadioButton)

  For Each row As ListViewItem In lvw.Items
    Dim rb As RadioButton = row.FindControl("rdbSelect")
      If rb IsNot Nothing AndAlso rb.Checked Then
         rb.Checked = False
      End If
  Next
  rb1.Checked = True
End Sub

然后当点击提交按钮时:

Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs)  Handles btnSubmit.Click

  For Each row As ListViewItem In lvw.Items
    Dim rb As RadioButton = row.FindControl("rdbSelect")
        Dim lbl As Label
        If rb IsNot Nothing AndAlso rb.Checked = True Then
            lbl = row.FindControl("StudentID")
            Session("StudentID") = lbl.Text
        End If
    Next

    Response.Redirect("~/TransferStudent.aspx")
End Sub
于 2011-05-04T12:50:47.550 回答
3

这个可能会好一点。。

我有一个用户控件,它本质上是中继器内的一组单选按钮,用户控件的每个实例都有一个名为 FilterTitle 的公共属性,每个实例都是唯一的。

将这两个属性添加到您的单选按钮中,将 FilterTitle 替换为您自己的公共属性名称

onclick='<%# "$(\"input[name$=btngroup_" + FilterTitle + "]\").removeAttr(\"checked\"); $(this).attr(\"checked\",\"checked\");" %>' GroupName='<%# "btngroup_" + FilterTitle  %>'

更简单..

onclick="$('input[name$=btngroup1]').removeAttr('checked'); $(this).attr('checked','checked');" GroupName="btngroup1"
于 2010-05-10T23:42:39.010 回答
2

为了完整起见,这是一个纯 Javascript 解决方案。

只需将此onclick属性添加到您的RadioButton元素(将GroupName替换为您RadioButton的 GroupName):

<asp:RadioButton ... GroupName="GroupName" onclick="SelectRadioButton('GroupName$',this)" ... />

并在您的页面中包含此 Javascript:

<script type="text/javascript">
function SelectRadioButton(regexPattern, selectedRadioButton)
    {
        regex = new RegExp(regexPattern);
        for (i = 0; i < document.forms[0].elements.length; i++)
        {
            element = document.forms[0].elements[i];
            if (element.type == 'radio' && regex.test(element.name))
            {
                element.checked = false;
            }
        }
        selectedRadioButton.checked = true;
    }
</script>
于 2011-12-07T08:46:37.780 回答
2

创建一个自定义控件并将 UniqueID 覆盖为列表视图 UniqueID + GroupName

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MYCONTROLS
{

[ToolboxData("<{0}:MYRADIOBUTTON runat=server></{0}:MYRADIOBUTTON >")]
public class MYRADIOBUTTON : RadioButton
{
    public override string UniqueID
    {
        get
        {
            string uid = base.UniqueID;
            //Fix groupname in lisview
            if (this.Parent is ListViewDataItem && GroupName != "")
            {
                uid = this.Parent.UniqueID;
                uid = uid.Remove(uid.LastIndexOf('$'));
                uid += "$" + GroupName;

            }
            return uid;


        }
    }

}
}

它是一个继承自 RadioButton 的自定义控件(公共类 MYRADIOBUTTON : RadioButton)。如果你在课堂上什么都不做,你会得到一个普通的 RadioButton。覆盖 UniqueId 您可以更改名称属性呈现方式的逻辑。为了仍然保持页面上其他控件的名称(列表视图之外)唯一,您可以从 ListView 获取 UniqueId 并将 GroupName 添加到该名称并将其添加到 RadioButton。

这解决了在列表视图的不同行上分组单选按钮的问题。您可能希望使用属性添加更多逻辑来打开/关闭此功能,使其表现得像普通的 RadioButton。

于 2013-01-22T00:13:34.360 回答
2

我知道这个问题有点老了,但我认为它可能会对某人有所帮助,因此发布我对这个问题的解决方案。

这个问题有2个部分:

  1. 防止一次选择多个单选按钮。
  2. 要知道在服务器端代码中单击了哪个单选按钮。

我在中继器中的单选按钮有类似的问题。我在这里找到了部分解决方案: Simple fix for Radio Button controls in an ASP.NET Repeater using jQuery

请阅读以上文章以了解该问题。我参考了这篇文章,这是很好的帮助。如上所述,这个问题有两个部分,首先是防止一次选择多个单选按钮。其次,要知道在服务器端代码中单击了哪个单选按钮。上述文章中发布的解决方案仅适用于第一部分。但是,那里编写的代码以及那里发布的解决方案更新对我不起作用。所以我不得不对其进行一些修改以使其正常工作。这是我的解决方案。

我想用投票按钮创建投票。我的单选按钮 (ID) 的名称是 PollGroupValue,其中 Groupname 在转发器中设置为 PollGroup。记住 ASP.net 中的 Groupname 属性在生成的 html 中呈现为 name 属性。我的代码如下:

<script type="text/javascript">

/*  Step-01: */
$(document).ready(function () {

    /*  Step-02: */
    $("[name*='PollGroup']").each(function () {
        $(this).attr('ci-name', $(this).attr('name'));
    });

    /*  Step-03: */
    $("[name*='PollGroup']").attr("name", $("[name*='PollGroup']").attr("name"));

    $('#Poll1_BtnVote').click(function (e) {

        /* Step - 04:  */
        if ($("[name*='PollGroup']").filter(':checked').length == 0) {
            alert('Please select an option.');
            e.preventDefault();
        }

        /* Step - 05:  */
        $("[name*='PollGroup']").each(function () {
            $(this).attr('name', $(this).attr('ci-name'));
        });
    });
});

第 1 步:每当在中继器中使用单选按钮时,它的组名都会更改,因为 asp.net 会更改它以使其唯一。因此,每个单选按钮都有不同的组名(客户端生成的标记中的名称属性)。因此,用户可以同时选择所有选项。如后续注释所述,此问题已通过使用 jquery 代码解决。

第 2 步:此代码块创建一个名为 ci-name 的新客户属性,并将 name 属性的原始值复制到这个新的自定义属性中。这个过程对轮询中的每个单选按钮重复。这一步将在后面的步骤中帮助我们。

步骤 3:此代码块将 poll 中所有单选按钮的名称属性值设置为第一个单选按钮的名称属性值。此步骤可防止用户一次选择多个选项。

第 4 步:此代码在投票按钮单击事件的事件处理程序中,检查用户是否至少选中了一个选项。如果他没有,则会显示一条错误消息。

第 5 步:此代码在投票按钮单击事件的事件处理程序中,将所有单选按钮的名称属性值设置为其原始值。这是通过从自定义属性 ci-name 复制值来实现的。这允许 asp.net 服务器端代码知道实际单击了哪个按钮。

于 2015-01-01T08:59:14.347 回答
1

我也对这个错误感到困惑,并决定放弃中继器,转而使用内部控件动态构建一个表。在您的用户控件或页面上,只需添加以下元素:

<asp:Table ID="theTable" runat="server">
    <asp:TableHeaderRow runat="server">
        <asp:TableHeaderCell runat="server" Text="Column 1"/>
        <asp:TableHeaderCell runat="server" Text="Column 2"/>
        <asp:TableHeaderCell runat="server" Text="Column 3"/>
    </asp:TableHeaderRow>
</asp:Table>

然后在代码后面添加单选按钮和其他所需控件的数据行。您当然可以对其他元素(如 DIV)执行相同操作:

<div runat="server" ID=theDiv">
</div>

但是,让我们仍然希望 ASP.NET 团队能够解决这个与转发器和列表视图有关的不幸问题。我仍然喜欢中继器控件并尽可能使用它。

于 2011-02-03T17:54:58.227 回答
1

这是一种使用反射的纯服务器端方法。RadioButton控件使用该属性UniqueGroupName来确定组名。组名缓存在_uniqueGroupName字段内。通过使用反射设置此字段,我们可以覆盖默认组名,并在转发器中的所有单选按钮中使用相同的组名。请注意,此代码必须在“RadioButton”控件的“PreRender”事件中运行,以确保新组名在回发中保持不变。

protected void rbOption_PreRender(object sender, EventArgs e)
{
    // Get the radio button.
    RadioButton rbOption = (RadioButton) sender;

    // Set the group name.
    var groupNameField = typeof(RadioButton).GetField("_uniqueGroupName", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
    groupNameField.SetValue(rbOption, "MyGroupName");

    // Set the radio button to checked if it was selected at the last post back.
    var groupValue = Request.Form["MyGroupName"];

    if(rbOption.Attributes["value"] == groupValue)
    {
        rbOption.Checked = true;
    } 
}

RadioButton源代码:http ://reflector.webtropy.com/default.aspx/Net/Net/3@5@50727@3053/DEVDIV/depot/DevDiv/releases/whidbey/netfxsp/ndp/fx/src/xsp/System /Web/UI/WebControls/RadioButton@cs/2/RadioButton@cs

于 2015-12-22T03:53:34.380 回答
0

这可能不是每个人的理想解决方案,但我使用 jQuery 进行了以下操作。

<asp:RadioButton ID="rbtnButton1" groupName="Group1" runat="server" /> <asp:RadioButton ID="rbtnButton2" groupName="Group1" runat="server" />

etc...

然后在您的母版页中包含以下代码。(或您的所有页面)

$(function() {
//This is a workaround for Microsoft's GroupName bug.  
//Set the radio button's groupName attribute to make it work.
$('span[groupName] > input').click(function() {
    var element = this;
    var span = $(element).parent();
    if (element.checked) {
        var groupName = $(span).attr('groupName');
        var inputs = $('span[groupName=' + groupName + '] > input')
        inputs.each(function() {
            if (element != this)
                this.checked = false;
        });
    }
});

});

于 2010-03-18T17:28:42.510 回答
0

HtmlInputControl.RenderAttributes()通过忽略RenderedNameAttribute属性来解决方法的自定义控件/覆盖:

/// <summary>
/// HACK:  For Microsoft&apos;s bug whereby they mash-up value of the "name" attribute.
/// </summary>
public class NameFixHtmlInputRadioButton : HtmlInputRadioButton
{
    protected override void RenderAttributes(HtmlTextWriter writer)
    {
        // BUG:  Usage of 'HtmlInputControl.RenderedNameAttribute'
        // writer.WriteAttribute("name", this.RenderedNameAttribute);
        writer.WriteAttribute(@"name", Attributes[@"Name"]);

        Attributes.Remove(@"name");

        var flag = false;
        var type = Type;

        if (! string.IsNullOrEmpty(type))
        {
            writer.WriteAttribute(@"type", type);
            Attributes.Remove(@"type");
            flag = true;
        }

        base.RenderAttributes(writer);

        if (flag && DesignMode)
        {
            Attributes.Add(@"type", type);
        }

        writer.Write(@" /");
    }
}
于 2016-02-10T18:09:32.770 回答
0

我使用相同的技术用 jquery 取消选中其他收音机请在下面找到代码

<asp:RadioButton ID="rbSelectShiptoShop" runat="server" onchange="UnCheckRadio(this);" CssClass="radioShop" />

和下面的脚本

function UnCheckRadio(obj) {
           $('.radioShop input[type="radio"]').attr('checked', false);
           $(obj).children().attr('checked', true);
       }
于 2017-01-04T08:23:42.013 回答