如何使用与UpdatePanel类似的标记使用内部属性创建ASP.NET用户控件?

And*_*rew 9 asp.net user-controls

我正在创建一个用户控件,我希望它具有内部属性以及普通属性.虽然控件的实际功能与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>
Run Code Online (Sandbox Code Playgroud)

也可以接受将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>
Run Code Online (Sandbox Code Playgroud)

但是,ControlEvents标记应该只允许这个特定的标记,而不是正常的服务器标记或任何东西.

我理解如何获取内部ContentTemplate渲染内容(在我看来Page_Init,我使用的ITemplate.InstantiateIn(placeholderControl)方法).那部分工作正常.我遇到麻烦的地方是让ControlEvent部分工作.我可以在代码隐藏中创建内部属性,如:

[TemplateInstance(TemplateInstance.Multiple)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(ControlEvent))]
public List<ControlEvent> ControlEvents { get; set; }
Run Code Online (Sandbox Code Playgroud)

这样做,ASP.NET似乎明白我想要一个ControlEvents标签.但是,我无法识别属性,无论是内部属性还是属性.相反,如果我尝试第一种类型的标记,我会得到一个运行时解析器错误:"属性'ControlEvents'没有名为'ControlName'的属性." 如果我尝试第二种类型的标记,我会NullReferenceException在运行时获得一个解析器错误,并在该<ns:ControlEvent>行生成错误.

我已经在网上查了一下,但是我没有找到一个很好的例子或解释如何完成我想要做的事情ControlEvent或者ControlEvents.我错过了什么?有人能指点我这里的好榜样吗?

谢谢!

编辑:

事实证明,一些问题是由于我如何使用它将控件注册到页面.如果我使用:

<%@ Register Src="~/Controls/MyControl.ascx" TagPrefix="ns" TagName="MyControl" %>
Run Code Online (Sandbox Code Playgroud)

似乎控件本身在标记中被识别,但事实ns:ControlEvent并非如此.如果我改为Register:

<%@ Register Namespace="Namespace.Controls" TagPrefix="ns" Assembly="MyAssembly" %>
Run Code Online (Sandbox Code Playgroud)

它的作用就是理解控件本身(前提runat="server"是它包含在ns:ControlEvent标签中).但是,MyControl的子控件不再被实例化或渲染,并且控件的事件例如Page_Init并且Page_Load没有被触发.

经过多次搞乱后,我发现我似乎需要两个Register指令.这看起来像是一个混乱的"解决方案",它甚至没有解决所有问题,因为(因为)(至少一些)我的控件中的某些标记没有渲染,尽管模板控件(ContentTemplate)似乎再次起作用.

我可以在这里丢失哪些东西会使这个控件使用起来不那么混乱,这会让这个控件实际上正确地渲染一切?

Nar*_*man 10

属性必须作为a Collection而不是a 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) });
        }
    }
Run Code Online (Sandbox Code Playgroud)

HTH.