我正在创建一个用户控件,我希望它具有内部属性和普通属性。虽然控件的实际功能与UpdatePanel无关,但我试图创建具有类似ASPX标记的东西。设计页面的开发人员应该能够使用我的控件,如:
<ns:MyControl ID="someID" runat="server" SomeOtherAttribute="true">
<ContentTemplate>
<asp:Label ID="someLabel" runat="server" Text="Normal page markup and controls should go here" /><br />
<p>This should be OK too.</p>
</ContentTemplate>
<ControlEvent ControlName="idOfOtherControl" Event="Click" />
<ControlEvent ControlName="idOfSomeOtherControl" Event="MouseOver" />
</ns:MyControl>
同样可以接受的是将ControlEvent
标记包装在其他标记中,更像是使用UpdatePanel时发生的情况:
<ns:MyControl ID="someID" runat="server" SomeOtherAttribute="true">
<ContentTemplate>
<asp:Label ID="someLabel" runat="server" Text="Normal page markup and controls should go here" /><br />
<p>This should be OK too.</p>
</ContentTemplate>
<ControlEvents>
<ns:ControlEvent ControlName="idOfOtherControl" Event="Click" />
<ns:ControlEvent ControlName="idOfSomeOtherControl" Event="MouseOver" />
</ControlEvents>
</ns:MyControl>
但是,ControlEvents
标记应该只允许这个特定的标记,而不是普通的服务器标记或任何东西。
我了解如何让ContentTemplate
内的内容呈现(在我的Page_Init
中,我使用ITemplate.InstantiateIn(placeholderControl)
方法)。那部分工作正常。我遇到麻烦的地方是让ControlEvent
部分工作。我可以在代码隐藏中创建内部属性,如:
[TemplateInstance(TemplateInstance.Multiple)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(ControlEvent))]
public List<ControlEvent> ControlEvents { get; set; }
通过这样做,ASP.NET似乎明白我想要一个ControlEvents
标记。但是,我无法识别属性,无论是内部属性还是属性。相反,如果我尝试第一种类型的标记,我会得到一个运行时解析器错误:“属性'ControlEvents'没有名为'ControlName'的属性。”如果我尝试第二种类型的标记,我会在运行时获得NullReferenceException
作为解析器错误,并在<ns:ControlEvent>
行生成错误。
我已经在网上查了一下,但是我没有找到一个很好的例子或解释,说明如何完成我要对ControlEvent
或ControlEvents
做的事情。我错过了什么?有人能指点我这里的好榜样吗?
谢谢!
修改
事实证明,部分问题是由于我如何使用它将控件注册到页面。如果我在使用:
<%@ Register Src="~/Controls/MyControl.ascx" TagPrefix="ns" TagName="MyControl" %>
似乎控件本身在标记中被识别,但ns:ControlEvent
不是。如果我将Register
更改为:
<%@ Register Namespace="Namespace.Controls" TagPrefix="ns" Assembly="MyAssembly" %>
只要理解控件本身(假设runat="server"
标记中包含ns:ControlEvent
),就可以了。但是,MyControl的子控件不再被实例化或呈现,并且Page_Init
和Page_Load
等控件的事件未被触发。
经过多次搞乱后,我发现我似乎需要两个Register
指令。这似乎是一个混乱的“解决方案”,它甚至没有真正解决所有问题,因为(因为)我的控件中至少有一些标记没有渲染,尽管模板控件(ContentTemplate
)似乎再次工作。
我可以在这里遗漏哪些东西会使这个控件使用起来不那么混乱,这会让这个控件实际上正确地渲染一切?
答案 0 :(得分:10)
必须将属性标记为Collection
,而不是List
;除此之外,最重要的是要记住,父控件必须设置 [ParseChildren(true)]
属性,否则集合将为null
。
以下(服务器控制)示例按预期工作:
public class ControlEvent
{
public string ControlName { get; set; }
public string Event { get; set; }
}
[ParseChildren(true)]
public class SampleControl : System.Web.UI.Control, INamingContainer
{
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(SampleControl))]
public ITemplate ContentTemplate { get; set; }
[MergableProperty(false), PersistenceMode(PersistenceMode.InnerProperty), DefaultValue((string)null)]
public Collection<ControlEvent> ControlEvents { get; set; }
protected override void CreateChildControls()
{
base.CreateChildControls();
if (ContentTemplate != null)
ContentTemplate.InstantiateIn(this);
if (null != ControlEvents)
foreach (ControlEvent e in ControlEvents)
Controls.Add(new Label() { Text = string.Format("ControlName:{0}, Event:{1}", e.ControlName, e.Event) });
}
}
HTH。