I need to develop a template-like user control, which would accept any arbitrary content, including other controls.
WmlCard.ascx
<asp:PlaceHolder ID="phContent" runat="server">
<card id="<%= Me.CardId %>" title="<%= Me.Title %>">
<p>
<%= Me.InnerText %>
</p>
</card>
</asp:PlaceHolder>
It would be used this way:
ListaTelefonica.aspx
<%@ Register TagPrefix="sic" TagName="Card" Src="~/path/to/WmlCard.ascx"%>
<sic:Card ID="BuscaCard" runat="server" CardId="busca" title="Lista TelefĂ´nica" Visible="false">
<asp:Literal ID="SomeLiteral" runat="server" Visible="false">Some text<br /></asp:Literal>
<asp:Literal ID="RuntimeFilledLiteral" runat="server" Visible="false" /><br /></asp:Literal>
Any text.
</sic:Card>
It is unfortunate that Ascx user controls have to inherit System.Web.UI.UserControl
. If I could inherit System.Web.UI.WebControls.WebControl
, for example, it would be a piece of cake.
My problem is similar to this one, but instead of just text the control should accept any other control inside it.
I tried <ParseChildren(False)>
and overriding AddParsedSubObject(Object)
in WmlCard
, but it is not a solution because the html is rendered before the Page Load, making it pointless to change the value of RuntimeFilledLiteral.Text
in a page's Page_Load, for example.
First error I got:
Parser Error Message: Type 'ASP.sic_sicphone_usercontrol_wmlcard_ascx' does not have a public property named 'Literal'.
After adding <PersistenceMode(PersistenceMode.InnerDefaultProperty), ParseChildren(True, "InnerText")>
:
The 'InnerText' property of 'sic:Card' does not allow child objects.
Same as above but changing WmlCard's property InnerText
type from String
to List(Of Object)
:
Literal content ('Any text.') is not allowed within a 'System.Collections.IList'.
After adding <ParseChildren(False)>
and overriding AddParsedSubObject
:
No error message, but WmlCard's content is rendered to html before I have a chance to change its inner controls runtime properties.
If I change WmlCard to inherit System.Web.UI.WebControls.PlaceHolder
instead of System.Web.UI.UserControl
:
'...UserControl.WmlCard' is not allowed here because it does not extend class 'System.Web.UI.UserControl'.
Found a valid way:
1) Put nothing inside my control (WmlCard.ascx).
2) Added the attribute <ParseChildren(False)>
to WmlCard.
3) Added a handler to the event PreRender on WmlCard:
Private Sub Page_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
Dim litBefore As New Literal()
litBefore.Text = String.Format("<card id=""{0}"" title=""{1}""><p>", Me.CardId, Me.Title)
Dim litAfter As New Literal()
litAfter.Text = "</p></card>"
Me.Controls.AddAt(0, litBefore)
Me.Controls.Add(litAfter)
End Sub
And that's it. Everything is working. Thanks for your help thinking thru this!