ASP.NET RadioButton弄乱了名字(groupname)

时间:2008-12-18 09:50:21

标签: asp.net radio-button

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

转发器将radiobutton设置为使用默认ASP.NET命名约定生成的id和名称,使每个radiobutton成为一个完整的“组”。这意味着所有的无线电按钮彼此独立,遗憾的是,这意味着我可以同时选择所有的无线电按钮。 radiobutton具有用于设置公共名称的聪明属性“groupname”,因此它们被组合在一起,因此应该是相关的(因此我一次只能选择一个)。问题是 - 这不起作用 - 转发器确保id和名称(控制分组)不同。

由于我使用转发器(可能是listview或任何其他模板化的数据绑定控件),我无法使用RadioButtonList。那么这让我离开了什么?

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

如果你没有比我发布的更好的解决方案,你仍然非常欢迎你发表你的想法 - 至少我会知道我的朋友'杰克'是关于ASP.NET有时会搞砸的事情;)< / p>

14 个答案:

答案 0 :(得分:8)

ASP.NET提示:在Repeater中使用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作为Repeater的名称,并使用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/

答案 1 :(得分:7)

Google-fu:asp.net radiobutton repeater problem

确实是身份损失的不幸后果。我的想法是创建一个 - 或者选择一个可用的 - 自定义控件,在客户端上添加对同名的支持。

答案 2 :(得分:6)

Vladimir Smirnov已经创建了一个很棒的自定义控件来解决这个问题。我们在我们的项目中一直使用GroupRadioButton,它一直与转发器内部创建的单选按钮完美配合,转发器外部的其他按钮都是同一组的一部分。

答案 3 :(得分: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>

答案 4 :(得分:5)

我知道这是一篇旧帖子,但这是我最后用listview做的事情。我的listview受到VB代码隐藏的约束,所以我不确定这是否适用于转发器,但我想它可能类似。

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

此解决方案避免使用JavaScript和jQuery,并完全忽略GroupName问题。它并不理想,但它的作用是(I)预期的。我希望这对其他人有帮助。

标记:

<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

答案 5 :(得分:3)

这可能会好一点......

我有一个usercontrol,它实际上是一个转发器内的一组radiobuttons,usercontrol的每个实例都有一个名为FilterTitle的公共属性,每个实例都是唯一的。

将这两个属性添加到您的radiobutton,用您自己的公共属性名称

替换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"

答案 6 :(得分: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>

答案 7 :(得分:2)

创建自定义控件并将UniqueID覆盖到listview 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,您可以更改name属性的呈现方式。 要使名称对页面上的其他控件(列表视图外)保持唯一,您可以从ListView获取UniqueId并将GroupName添加到该名称并将其添加到RadioButton。

这解决了在listview中的不同行上分组RadioButtons的问题。您可能希望添加一些带有属性的逻辑来打开/关闭此功能,使其行为类似于普通的RadioButton。

答案 8 :(得分:2)

我知道这个问题有点老了,但我认为这可能会对某些人有所帮助,因此我可以解决这个问题。

这个问题有两个部分:

  1. 防止一次选择多个单选按钮。
  2. 要知道在服务器端代码中单击了哪个单选按钮。
  3. 我在Repeater的Radio按钮上遇到了类似的问题。我找到了部分解决方案: 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的新custome属性,并将name属性的原始值复制到此新自定义属性中。轮询中的每个单选按钮都会重复此过程。这一步将在后面的步骤中帮助我们。

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

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

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

答案 9 :(得分: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团队能够解决转发器和列表视图这个不幸的问题。我仍然喜欢转发器控制并尽可能使用它。

答案 10 :(得分: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

答案 11 :(得分: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;
        });
    }
});

});

答案 12 :(得分: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(@" /");
    }
}

答案 13 :(得分:0)

我使用相同的Technic取消选中其他收音机和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);
       }