为什么ASP.Net RadioButton和CheckBox在Span内部呈现?

时间:2009-06-15 17:32:43

标签: asp.net webforms

我希望如此:

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

...像这样渲染(为简单起见,删除了一些属性)

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

...事实上,RadioButtonCheckBox包含span标记,CSS类会在那里应用。

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

这是否有原因,是否有办法避免它?它使jQuery选择器变得丑陋,因为你不能用以下方法捕获所有这些:

$("input.myClass")

当然这只是:

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

......但那很难看。我可以编写自己的选择器,但又不如它应该优雅。

7 个答案:

答案 0 :(得分:113)

这让我疯狂,直到找到inputAttributes属性。

例如,以下是如何在复选框控件上直接添加类而不使用span废话:

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

答案 1 :(得分:48)

System.Web.UI.WebControls命名空间中的Web控件在不同的浏览器中可能会有不同的呈现方式。你不能指望他们总是渲染相同的元素。他们可能会添加他们认为需要的任何内容,以使其在特定浏览器中运行。

如果您想要控制如何将控件呈现为html,则应该使用System.Web.UI.HtmlControls命名空间中的控件。那就是:

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

它们将呈现为相应的html元素,不添加任何额外元素。这当然意味着您必须对浏览器兼容性负责,因为控件没有。此外,这些控件没有WebControls命名空间中控件的所有功能。

答案 2 :(得分:5)

默认情况下,每个WebControl都会呈现为<span>标记,以及控件作者添加的任何自定义呈现。

编写自定义WebControl时,您通常要做的第一件事就是覆盖“TagKey”属性来渲染div,或者除了span之外的其他东西。此属性的默认值为HtmlTextWriterTag.Span。

您可以对复选框项进行子类化并覆盖TagKey属性以呈现其他内容,但是您必须处理将所有复选框复制到您自己的版本中。

答案 3 :(得分:3)

我遇到了这个问题,并尝试使用控制适配器来解决它。

有关对单选按钮列表执行此操作的示例,请参阅here

我最终将其作为我的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(" />");

    }
}

这增加了我的浏览器文件 -

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

当然,这有一些缺点。除了the above link中提到的那些,如果你没有暗示所有内容,你也会失去功能(上面的代码不允许检查单选按钮)。有一些CSS友好的控制适配器,但它们不包括单选按钮控件。可以使用Reflector将默认控件适配器作为起点。

答案 4 :(得分:1)

普通的RadioButton通常没有跨度。如果设置CssClass,Style,Enabled属性,则使用span渲染RadioButton。当我需要使用客户端脚本操作单选按钮时,这种不一致是一个真正的痛苦。我通常做的是应用一个虚拟的CssClass,以便始终一致地渲染一个跨度。

答案 5 :(得分:0)

发现类似的问题,写了一个简单的基于jQuery的函数来启用/禁用复选框和父级别

function resetChk(ctl, bEnable) { 

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

        }

答案 6 :(得分:0)

我认为这是最好的方式:


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

在自定义控件中使用它:


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