web-dev-qa-db-fra.com

Pourquoi ASP.Net RadioButton et CheckBox sont-ils rendus dans un span?

Je m'attendrais à ceci:

<asp:CheckBox    ID="CheckBox1"    runat="server" CssClass="myClass" />
<asp:RadioButton ID="RadioButton1" runat="server" CssClass="myClass" />
<asp:TextBox     ID="TextBox1"     runat="server" CssClass="myClass" />

... pour rendre comme ceci (avec quelques attributs supprimés pour plus de simplicité) :

<input id="CheckBox1"    type="checkbox" class="myClass" />
<input id="RadioButton1" type="radio"    class="myClass" />
<input id="TextBox1"     type="text"     class="myClass" /> 

... alors qu'en réalité, les variables RadioButton et CheckBox sont entourées d'une balise span et que la classe CSS y est appliquée.

<span class="myClass"><input id="CheckBox1"    type="checkbox" /></span> 
<span class="myClass"><input id="RadioButton1" type="radio"    /></span> 
<input type="text" id="TextBox1" class="myClass" /> 

Y a-t-il une raison à cela et existe-t-il un moyen de l'éviter? Les sélecteurs jQuery sont laids, car vous ne pouvez pas tous les attraper avec:

$("input.myClass")

Accordé ça va juste pour:

$("input.myClass, span.myClass input")

... mais c'est moche. Je pourrais écrire mon propre sélecteur, mais là encore, pas aussi élégant qu'il devrait l'être.

51
Mark

Les contrôles Web de l'espace de noms System.Web.UI.WebControls peuvent s'afficher différemment selon les navigateurs. Vous ne pouvez pas compter sur eux pour rendre toujours les mêmes éléments. Ils peuvent ajouter tout ce qui, à leur avis, est nécessaire pour que cela fonctionne dans le navigateur spécifique.

Si vous souhaitez avoir un contrôle quelconque sur la manière dont les contrôles sont rendus au format HTML, vous devez plutôt utiliser les contrôles de l'espace de noms System.Web.UI.HtmlControls. C'est:

<input type="checkbox" id="CheckBox1" runat="server" class="myClass" />
<input type="radio" name="RadioButton1" runat="server" class="myClass" />
<input type="text" id="TextBox1" runat="server" class="myClass" />

Ils seront rendus comme l’élément html correspondant, sans ajout d’éléments supplémentaires. Bien entendu, cela signifie que vous devrez assumer la responsabilité de la compatibilité du navigateur, contrairement au contrôle. En outre, ces contrôles ne possèdent pas toutes les fonctionnalités des contrôles de l'espace de noms WebControls.

47
Guffa

Cela me rendait fou jusqu'à ce que je trouve la propriété inputAttributes.

Par exemple, voici comment ajouter une classe directement sur le contrôle de case à cocher sans le sens absurde: 

myCheckBoxControl.InputAttributes.Add("class", "myCheckBoxClass")
113
JohnFx

Chaque WebControl est rendu par défaut sous la forme d'une balise <span>, plus tout rendu personnalisé ajouté par l'auteur du contrôle. 

Une des premières choses que vous faites habituellement lorsque vous écrivez un contrôle Web personnalisé est de remplacer la propriété " TagKey " pour restituer une div ou autre chose qu'une étendue. La valeur par défaut de cette propriété est HtmlTextWriterTag.Span.

Vous pouvez sous-classer vos éléments de case à cocher et remplacer la propriété TagKey pour obtenir autre chose, mais vous devez ensuite créer toutes vos cases à cocher dans votre propre version.

5
womp

Je suis tombé sur ce problème et je suis tenté de le résoudre en utilisant des adaptateurs de contrôle.

Voir ici pour un exemple de cette opération dans une liste de boutons radio.

Je me suis retrouvé avec ceci comme mon RadioButtonAdaptor-

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.Adapters;

public class RadioButtonAdapter : WebControlAdapter
{
    protected override void Render(HtmlTextWriter writer)
    {
        RadioButton targetControl = this.Control as RadioButton;

        if (targetControl == null)
        {
            base.Render(writer);

            return;
        }

        writer.WriteBeginTag("input");
        writer.WriteAttribute("type", "radio");
        writer.WriteAttribute("name", targetControl.GroupName);
        writer.WriteAttribute("id", targetControl.ClientID);            

        if (targetControl.CssClass.Length > 0)
        {
            writer.WriteAttribute("class", targetControl.CssClass);
        }      

        writer.Write(" />");

    }
}

Et cela ajouté à mes navigateurs de fichiers

<browser refID="Default">
        <controlAdapters>            
            <adapter controlType="System.Web.UI.WebControls.RadioButton"
               adapterType="RadioButtonAdapter" />
        </controlAdapters>
</browser>

Bien sûr, il y a des inconvénients à cela. En plus de ceux mentionnés dans le lien ci-dessus , vous perdez également des fonctionnalités si vous n'impliquez pas tout (le code ci-dessus ne permet pas de cocher un bouton radio). Il existe des adaptateurs de contrôle conviviaux pour CSS, mais ils ne couvrent pas le contrôle des boutons radio. Il est possible d’utiliser Reflector pour obtenir l’adaptateur de contrôle par défaut comme point de départ.

3
Spongeboy

Le RadioButton simple est souvent rendu sans une étendue. Si vous définissez les propriétés CssClass, Style, Enabled, RadioButton est rendu avec une étendue. Cette incohérence est une vraie douleur lorsque je dois manipuler le bouton radio avec des scripts côté client. Ce que je fais habituellement, c’est d’appliquer une classe factice CssClass afin qu’elle rende toujours une plage de manière cohérente.

1
Li Chen

le meilleur moyen que je pense est la suivante:


    public class HtmlTextWriterNoSpan : HtmlTextWriter
    {
        public HtmlTextWriterNoSpan(TextWriter textWriter) : base(textWriter)
        { 
        }

        protected override bool OnTagRender(string name, HtmlTextWriterTag key)
        {
            if (name == HtmlTextWriterTag.Span)
            {
                return false;
            }

            return base.OnTagRender(name, key);
        }
    }

pour l'utiliser dans le contrôle personnalisé:


    protected override void Render(HtmlTextWriter writer)
    {
        writer = new HtmlTextWriterNoSpan(writer);
        base.Render(writer);
        // HERE MORE CODE
    }
0
Jimmi

Problème similaire trouvé, écrit une fonction simple basée sur jQuery pour activer/désactiver la case à cocher et la plage parent

function resetChk(ctl, bEnable) { 

            if (bEnable){
                ctl.removeAttr('disabled').parent().removeAttr('disabled');
            }else{
                ctl.attr('disabled', true).parent().attr('disabled', true);
            }

        }
0
Stas Svishov