I am creating a user control that I wish to have inner properties as well as normal attributes. Although the actual function of the control has nothing to do with, say, UpdatePanel, I am trying to create something with similar ASPX markup. The developer designing the page should be able to use my control like:
<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>
Also acceptable would be wrapping the ControlEvent
tags in some other tag, more like what happens when using 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>
But, the ControlEvents
tag should only allow this one particular tag, not normal server markup or anything.
I understand how to get the content inside ContentTemplate
to render (in my Page_Init
, I use the ITemplate.InstantiateIn(placeholderControl)
method). That part works fine. Where I'm having trouble is getting the ControlEvent
part to work. I can create the inner property in the code-behind like:
[TemplateInstance(TemplateInstance.Multiple)]
[PersistenceMode(PersistenceMode.InnerProperty)]
[TemplateContainer(typeof(ControlEvent))]
public List<ControlEvent> ControlEvents { get; set; }
In so doing, ASP.NET does seem to understand that I want a ControlEvents
tag. But, I can't get properties, either inner properties or attributes, to be recognized. Instead, if I try the first type of markup, I get a runtime Parser Error: "Property 'ControlEvents' does not have a property named 'ControlName'." If I try the second type of markup, I get a NullReferenceException
as a parser error at runtime, with the error being generated at the <ns:ControlEvent>
line.
I've checked online, but I haven't found a good example or explanation of how to accomplish what I am trying to do with ControlEvent
or ControlEvents
. What am I missing? Could someone point me to a good example here?
Thanks!
Edit:
It turned out that some of the problem was due to how I had the control registered to the page using it. If I was using:
<%@ Register Src="~/Controls/MyControl.ascx" TagPrefix="ns" TagName="MyControl" %>
It appeared that the control itself was recognized in the markup, but ns:ControlEvent
was not. If I changed the Register
to:
<%@ Register Namespace="Namespace.Controls" TagPrefix="ns" Assembly="MyAssembly" %>
it worked as far as understanding the control itself (provided that runat="server"
was included in the ns:ControlEvent
tags). However, the child controls of MyControl were not being instantiated or rendered anymore, and events of the control such as Page_Init
and Page_Load
were not firing.
After much messing around, I figured out that I seem to need both Register
directives. This seems like a messy "solution," and it doesn't really even solve everything, as (for not) at least some of the markup in my control is not rendering, though the template control (ContentTemplate
) seems to be working again.
What kinds of things could I be missing here that would make this control less messy to use and that would make this control actually render everything correctly?
The properties must be implmented as a Collection
and not a List
; other than that, the most important thing to remember here is that the parent control must have [ParseChildren(true)]
attribute set for this to work, otherwise the collection will be null
.
The following (server-control) sample works as expected:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With