假设我有这个标记:
<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
类,我该如何实现?
我只想更深入地了解幕后的编译过程。
答案 0 :(得分:2)
通过深入研究Reference Source,您可以了解很多关于ASP.NET内部的知识。
事实证明,从未加前缀的HTML标记到HtmlControl子类的映射在名为HtmlTagNameToTypeMapper的内部类中是硬编码的:
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的内部类调用:
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);
}
}
没有公共API可以注册更多没有前缀的HTML控件类型。
在更本地化的范围内, 可以让父控件自定义如何解释其子控件的标记名称。为此,从ControlBuilder派生,重写GetChildControlType,并使用[ControlBuilder(typeof(...)] attribute修饰父控件类。
答案 1 :(得分:0)
当您向ASP.NET中的控件添加runat="server"
时,类型HtmlControl
(或其某些子类)的相应变量会自动添加到您的页面中(在设计器文件中)。这样您就可以将该控件作为变量访问。对于大多数常见的HTML控件,都有HtmlControl的子类(例如HtmlAnchor
用于锚点/链接标记)。其他控件(例如<div>
)获取HtmlGenericControl
类型。对于那些,您将标记(div
)指定为属性。所以你的Foo标签就像div一样:HtmlGenericControl
类型的变量,标签为“Foo”。
编辑:这适用于标准HTML元素。如果您创建ASP控件(例如<asp:TextBox...>
),则生成的变量将是子类或 WebControl 而不是 HtmlControl 。