为什么我的ASP.Net自定义控件在我的第一个子控件上呈现两个id属性?

时间:2009-10-21 14:04:48

标签: c# .net asp.net custom-controls

我正在编写一个继承自CompositeControl的小型ASP.Net自定义控件。该控件只是一个面板,其中包含两个子面板,每个子面板上都有一个标签。渲染时,我在HTML源代码中看到我的自定义控件的第一个子控件获得了两个id属性 - 第一个是自定义控件本身的id,第二个是我分配给第一个子控件的ID属性。为什么会这样?

代码:

[ToolboxData("<{0}:MessageBox runat=server></{0}:MessageBox>")]
public class MessageBox : CompositeControl {

    private Panel _MessageHeaderContainer = null;
    private Label _MessageHeaderLabel = null;
    private Panel _MessageDetailsContainer = null;
    private Label _MessageDetailsLabel = null;

    protected override HtmlTextWriterTag TagKey {
        get {
            return HtmlTextWriterTag.Div;
        }
    }

    protected override void CreateChildControls() {

        // Message header area.
        _MessageHeaderContainer = new Panel();
        _MessageHeaderContainer.ID = "HeaderContainer";
        _MessageHeaderContainer.CssClass = "__MessageBox_Container";
        this.Controls.Add(_MessageHeaderContainer);

        // Message header text.
        _MessageHeaderLabel = new Label();
        _MessageHeaderLabel.ID = "HeaderLabel";
        _MessageHeaderLabel.Text = "[ Header ]";
        _MessageHeaderContainer.Controls.Add(_MessageHeaderLabel);

        // Message details area.
        _MessageDetailsContainer = new Panel();
        _MessageDetailsContainer.ID = "DetailsContainer";
        this.Controls.Add(_MessageDetailsContainer);

        // Message details text.
        _MessageDetailsLabel = new Label();
        _MessageDetailsLabel.ID = "DetailsLabel";
        _MessageDetailsLabel.Text = "[ Details ]";
        _MessageDetailsContainer.Controls.Add(_MessageDetailsLabel);

    }

    protected override void RenderContents(HtmlTextWriter output) {
        AddAttributesToRender(output);

        // Render the box.
        _MessageHeaderContainer.RenderControl(output);
        _MessageDetailsContainer.RenderControl(output);
    }
}

ASPX页面中的用法:

<cc:MessageBox ID="ctlMessageBox" runat="server" />

HTML输出:

<div id="ctl00_ctl00_ctlMessageBox">
    <div id="ctl00_ctl00_ctlMessageBox" id="ctl00_ctl00_ctlMessageBox_HeaderContainer" class="__MessageBox_Container">
        <span id="ctl00_ctl00_ctlMessageBox_HeaderLabel">[ Header ]</span>
    </div><div id="ctl00_ctl00_ctlMessageBox_DetailsContainer">
        <span id="ctl00_ctl00_ctlMessageBox_DetailsLabel">[ Details ]</span>
    </div>
</div>

2 个答案:

答案 0 :(得分:4)

您可以通过完全删除RenderContents方法来解决此问题 - 请勿将其替换为任何内容。默认情况下,复合控件呈现其所有子控件。如果这样做,您的控件将生成干净的标记:

<div id="test">
    <div id="test_HeaderContainer" class="__MessageBox_Container">
     <span id="test_HeaderLabel">[ Header ]</span>
    </div>
    <div id="test_DetailsContainer">
     <span id="test_DetailsLabel">[ Details ]</span>
    </div>
</div>

正如您所指出的,AddAttributesToRender方法是罪魁祸首 - 它是一种方便的方法,可以呈现所有顶级控件的属性(当前上下文是否为顶级控件)。你可以这么称呼的唯一原因是你自己完全控制了渲染过程,并希望在一个语句中渲染顶层控件的所有属性。

答案 1 :(得分:-1)

这是ASP.NET分配自定义控件的ID。如果将自定义控件包装在Div或Span中(在自定义控件代码本身内,而不是在标记中),则会将ID分配给该ID而不是第一个内部“控件”。

这样的事情:

protected override void Render(HtmlTextWriter writer)
{
  AddAttributesToRender(writer);

  //must render tag or first inner control will get two IDs
  writer.RenderBeginTag(HtmlTextWriterTag.Span);

  //render child controls here...

  writer.RenderEndTag();
}