web-dev-qa-db-fra.com

ASP.NET RadioButton jouant avec le nom (nom de groupe)

J'ai obtenu un contrôle basé sur un modèle (un répéteur) répertoriant du texte et d'autres balises. Chaque élément est associé à un bouton radio, ce qui permet à l'utilisateur de sélectionner UN des éléments créés par le répéteur.

Le répéteur écrit le bouton radio en définissant son identifiant et son nom générés avec la convention de dénomination ASP.NET par défaut faisant de chaque bouton radio un "groupe" complet. Cela signifie que tous les boutons radio sont indépendants les uns des autres, ce qui signifie malheureusement que je peux sélectionner tous les boutons radio en même temps. Le radiobutton a l'attribut intelligent 'groupname' utilisé pour définir un nom commun, donc ils sont regroupés et doivent donc être dépendants (donc je ne peux en sélectionner qu'un à la fois). Le problème est - cela ne fonctionne pas - le répéteur s'assure que l'identifiant et donc le nom (qui contrôle le regroupement) sont différents.

Étant donné que j'utilise un répéteur (il pourrait s'agir d'une vue de liste ou de tout autre contrôle de modèle de données), je ne peux pas utiliser RadioButtonList. Alors, où est ce qu'il me laisse?

Je sais que j'ai déjà rencontré ce problème et l'ai résolu. Je sais que presque tous les programmeurs ASP.NET doivent l'avoir aussi, alors pourquoi ne puis-je pas rechercher sur Google une solution solide au problème? Je suis tombé sur des solutions pour imposer le regroupement par JavaScript (moche!) Ou même pour gérer les boutons radio comme des contrôles non serveur, me forçant à faire un Request.Form[name] pour lire l'état. J'ai également essayé d'expérimenter avec la substitution de l'attribut name sur l'événement PreRender - malheureusement, la page propriétaire et la page maître remplacent à nouveau ce nom pour refléter l'ID/nom complet, donc je me retrouve avec le même mauvais résultat.

Si vous n'avez pas de meilleure solution que ce que j'ai posté, vous êtes toujours les bienvenus pour poster vos réflexions - au moins je saurai que mon ami 'jack' a raison sur la façon dont ASP.NET est parfois gâché;)

36

Google-fu: problème de répéteur de radiobutton asp.net

En effet, une conséquence malheureuse de la mutilation. Ma prise serait de créer un - ou de choisir l'un des nombreux contrôles personnalisés disponibles - qui ajoute la prise en charge du même nom sur le client.

7
Cristian Libardo

Astuce ASP.NET: utilisation des contrôles RadioButton dans un répéteur

Voici le code de la fonction 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;
}

Le code est lié au répéteur via l'événement ItemDataBound. Pour qu'il fonctionne correctement, vous devez connaître le nom du contrôle Repeater, ainsi que le GroupName que vous attribuez aux RadioButtons. Dans ce cas, j'utilise rptPortfolios comme nom du répéteur et Portfolios comme nom de groupe:

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

}

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

8
Sheryar Nizar

Vladimir Smirnov a déjà créé un excellent contrôle personnalisé qui résout ce problème. Nous utilisons le GroupRadioButton dans nos projets et cela fonctionne parfaitement avec les boutons radio créés à l'intérieur d'un répéteur et d'autres à l'extérieur du répéteur faisant tous partie du même groupe.

6
Chris Magnuson

J'utilise le script 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>
6
Andrey Ilnitskiy

Je sais que c'est un vieux post, mais voici ce que j'ai fini par faire avec une vue de liste. Ma liste est liée à VB codebehind, donc je ne sais pas si cela fonctionnera bien avec un répéteur, mais j'imagine que cela pourrait être similaire.

Ce que j'ai fait, c'est gérer l'événement OnCheckChanged des boutons radio avec une fonction qui n'a pas sélectionné d'autres boutons radio. Ensuite, j'ai cherché le bouton radio sélectionné lorsque j'ai quitté la page.

Cette solution évite JavaScript et jQuery et ignore complètement le problème GroupName. Ce n'est pas idéal, mais cela fonctionne comme (je) m'y attendais. J'espère que c'est utile pour les autres.

Balisage:

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

Code:

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

Et puis lorsque le bouton Soumettre est cliqué:

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
Kit Z. Fox

Voici une solution Javascript pure pour être complète.

Ajoutez simplement cet attribut onclick à votre élément RadioButton (remplacez GroupName par le nom de groupe de votre RadioButton):

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

Et incluez ce Javascript dans votre page:

<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>
3
Saeb Amini

Cela pourrait être un peu mieux ..

J'ai un usercontrol qui est essentiellement un ensemble de boutons radio à l'intérieur d'un répéteur, chaque instance de l'usercontrol a une propriété publique appelée FilterTitle, qui est unique par instance.

ajoutez ces deux propriétés à votre radiobutton en remplaçant FilterTitle par votre propre nom de propriété publique

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

plus simplement..

onclick="$('input[name$=btngroup1]').removeAttr('checked'); $(this).attr('checked','checked');" GroupName="btngroup1"
3
tbilly

Je sais que cette question est un peu ancienne, mais je pense que cela pourrait aider quelqu'un, donc publier ma solution à ce problème.

Ce numéro se compose de 2 parties:

  1. Pour empêcher la sélection de plusieurs boutons radio à la fois.
  2. Pour savoir quel bouton radio a été cliqué dans le code côté serveur.

J'ai eu le même problème avec le bouton Radio dans Repeater. J'ai trouvé une solution partielle ici: correctif simple pour les contrôles de bouton radio dans un répéteur ASP.NET utilisant jQuery

Veuillez lire l'article ci-dessus pour comprendre le problème. J'ai référé cet article et cela m'a été d'une grande aide. Comme mentionné ci-dessus, ce problème se compose de deux parties. La première consiste à empêcher la sélection de plusieurs boutons radio à la fois. Deuxièmement, pour savoir quel bouton radio a été cliqué dans le code côté serveur. La solution publiée dans l'article ci-dessus n'a fonctionné pour moi que pour la première partie. Cependant, le code écrit là-bas ainsi que les mises à jour de la solution qui y étaient affichées ne fonctionnaient pas pour moi. J'ai donc dû le modifier un peu pour le faire fonctionner. Voici ma solution.

Je voulais créer un sondage avec le bouton Voter. Le nom de mon bouton radio (ID) est PollGroupValue avec Groupname défini sur PollGroup dans un répéteur. N'oubliez pas que l'attribut Groupname dans ASP.net est rendu comme attribut de nom dans le code HTML généré. Mon code est le suivant:

<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'));
        });
    });
});

Étape 1: Chaque fois qu'un bouton radio est utilisé dans le répéteur, son nom de groupe est changé, car asp.net le change de manière à le rendre unique. Par conséquent, chaque bouton radio obtient un nom de groupe différent (attribut de nom dans le balisage généré côté client). Pour cette raison, l'utilisateur peut sélectionner toutes les options en même temps. Ce problème est résolu en utilisant le code jquery comme expliqué dans les commentaires suivants.

Étape 2: ce bloc de code crée un nouvel attribut custome appelé ci-name et copie la valeur d'origine de l'attribut name dans ce nouvel attribut personnalisé. Ce processus se répète pour chaque bouton radio dans le sondage. Cette étape nous aiderait dans une étape ultérieure.

Étape 3: ce bloc de code définit la valeur des attributs de nom de tous les boutons radio dans le sondage à la valeur de l'attribut de nom du premier bouton radio. Cette étape empêche l'utilisateur de sélectionner plusieurs options à la fois.

Étape 4: Ce code dans le gestionnaire d'événements du bouton de vote, cliquez sur l'événement, vérifie si l'utilisateur a coché au moins une option. Si ce n'est pas le cas, un message d'erreur s'affiche.

Étape 5: Ce code dans le gestionnaire d'événements de l'événement de clic sur le bouton de vote, définit la valeur de l'attribut de nom de tous les boutons radio à leurs valeurs d'origine. Ceci est réalisé en copiant la valeur de l'attribut personnalisé ci-name. Cela permet au code côté serveur asp.net de savoir quel bouton a été réellement cliqué.

2
yatz

Créez un contrôle personnalisé et remplacez UniqueID par la vue de liste 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;


        }
    }

}
}

Il s'agit d'un contrôle personnalisé qui hérite de RadioButton (classe publique MYRADIOBUTTON: RadioButton). Si vous ne faites rien dans la classe, vous obtenez un RadioButton normal. En remplaçant l'UniqueId, vous pouvez modifier la logique de rendu de l'attribut de nom. Pour conserver le nom unique aux autres contrôles de la page (en dehors de la liste), vous pouvez obtenir le UniqueId de ListView et y ajouter GroupName et l'ajouter au RadioButton.

Cela résout le problème du regroupement des boutons radio sur différentes lignes dans une liste. Vous voudrez peut-être ajouter un peu plus de logique avec une propriété pour activer/désactiver cette fonctionnalité afin qu'elle se comporte comme un RadioButton normal.

2
Mårten Holm

J'ai également été déconcerté par ce bug et j'ai décidé de laisser tomber le répéteur en faveur de la construction dynamique d'une table avec les commandes à l'intérieur. Dans votre contrôle utilisateur ou sur votre page, ajoutez simplement les éléments suivants:

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

Ajoutez ensuite les lignes de données dans le code derrière avec des boutons radio et d'autres contrôles requis. Vous pouvez bien sûr faire de même avec d'autres éléments comme le DIV:

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

Mais espérons que l'équipe ASP.NET pourra résoudre ce malheureux problème avec les répéteurs et les vues de liste. J'aime toujours le contrôle du répéteur et je l'utilise autant que possible.

1
Lars Fastrup

Il s'agit d'une approche purement côté serveur utilisant la réflexion. Le contrôle RadioButton utilise la propriété UniqueGroupName pour déterminer le nom du groupe. Le nom du groupe est mis en cache dans le _uniqueGroupName champ. En définissant ce champ à l'aide de la réflexion, nous pouvons remplacer le nom de groupe par défaut et utiliser un nom de groupe identique sur tous les boutons radio d'un répéteur. Veuillez noter que ce code doit être exécuté dans l'événement "PreRender" du contrôle "RadioButton" pour garantir la persistance du nouveau nom de groupe dans les publications.

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 code source: 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

1
ACOMIT001

J'ai utilisé la même technique pour décocher d'autres radios avec jquery veuillez trouver ci-dessous le code

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

et script ci-dessous

function UnCheckRadio(obj) {
           $('.radioShop input[type="radio"]').attr('checked', false);
           $(obj).children().attr('checked', true);
       }
0
Ankit

Ce n'est peut-être pas la solution idéale pour tout le monde, mais j'ai fait ce qui suit en utilisant jQuery.

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

etc...

Incluez ensuite le code suivant dans votre page maître. (ou toutes vos pages)

$(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;
        });
    }
});

});

0
helios456

Un contrôle/remplacement personnalisé pour contourner la méthode HtmlInputControl.RenderAttributes() en ignorant la propriété 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(@" /");
    }
}
0
Dennis V McEnaney