HTML 标签如何转换为 HtmlControl?

How are HTML tags converted to HtmlControl?

假设我有这个标记:

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        <a runat="server" id="myLink" href="<%# Container.DataItem %>">Here</a>
    </ItemTemplate>
</asp:Repeater>

在代码隐藏中,我可以发现 <a> 被转换为 HtmlAnchor:

private void Repeater1_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    HtmlAnchor myLink = (HtmlAnchor)Repeater1.FindControl("myLink");
}

但是编译器怎么知道<a>HtmlAnchor呢?它是在编译器中硬编码的吗?

如果我写

<asp:Repeater ID="Repeater1" runat="server">
    <ItemTemplate>
        <Foo href="<%# Container.DataItem %>">Here</a>
    </ItemTemplate>
</asp:Repeater>

并希望将 <Foo> 标签转换为我的 HtmlFoo class,我该如何实现?

我只是想对幕后的编译过程有更深入的了解

当您将 runat="server" 添加到 ASP.NET 中的控件时,类型 HtmlControl 的相应变量(或其某些子类)会自动添加到您的页面(在设计器文件中).这样您就可以将该控件作为变量访问。对于最常见的 HTML 控件,有 HtmlControl 的子类(例如 HtmlAnchor 用于 anchor/link 标记)。其他控件(例如 <div>)获得 HtmlGenericControl 类型。对于那些,您将标记 (div) 指定为 属性。所以你的 Foo 标签会变成一个 div:一个类型为 HtmlGenericControl 的变量,标签为 "Foo".

编辑: 这是标准的 HTML 元素。如果您创建一个 ASP 控件(例如 <asp:TextBox...>,那么结果变量将是一个子类或 WebControl 而不是 HtmlControl.

您可以通过深入研究 Reference Source.

来了解 ASP.NET 的很多内部结构

事实证明,从无前缀 HTML 标签到 HtmlControl subclasses 的映射被硬编码在一个名为 HtmlTagNameToTypeMapper:[=16 的内部 class 中=]

static Hashtable _tagMap;

Type ITagNameToTypeMapper.GetControlType(string tagName, IDictionary attributeBag) {
    Type controlType;

    if (_tagMap == null) {
        Hashtable t = new Hashtable(10, StringComparer.OrdinalIgnoreCase);
        t.Add("a", typeof(HtmlAnchor));
        t.Add("button", typeof(HtmlButton));
        t.Add("form", typeof(HtmlForm));
        // [and much more...]
        _tagMap = t;
    }

    // [...]
}

GetControlType 由另一个名为 MainTagNameToTypeMapper:

的内部 class 调用
int colonIndex = tagName.IndexOf(':');
if (colonIndex >= 0) {
    // [...]
}
else {
    // There is no prefix.
    // Try the Html mapper if allowed
    if (fAllowHtmlTags) {
        return _htmlMapper.GetControlType(tagName, attribs);
    }
}

没有 public API 来注册更多无前缀的 HTML 控件类型。

在更本地化的范围内,父控件可以自定义其子控件的标签名称的解释方式。为此,派生自 ControlBuilder,覆盖 GetChildControlType, and decorate the parent control class with the [ControlBuilder(typeof(...)] attribute.