Basically, I have a custom templated control with a custom data container class. When a developer adds an instance of my control to a page, they can define the controls in the LayoutTemplate however they like, as follows:
<ml:MyControl id="MyControl1" runat="server">
<LayoutTemplate>
<span><%#Container.ErrorMessage%></span>
</LayoutTemplate>
</ml:MyControl>
This example renders on the page like this:
<span id="MyControl1"><span>
<span>ml_errormessage</span>
</span></span>
I would like my control to automatically move the "ml_errormessage" (databound content from Container.ErrorMessage - hard coded token in the property) to be a class of its containing element to make it easier for jQuery to use a selector to find the element and dynamically insert the error message client side. More importantly, I would like it moved out of the way so the class name doesn't get replaced by the content and jQuery can find it as many times as it needs to during the page lifecycle. In other words, I would like the output to look like this without the developer changing the input template or resort to using custom controls in the template:
<span id="MyControl1"><span>
<span class="ml_errormessage"></span>
</span></span>
I would like to move the value using the controls collection rather than resorting to string parsing of the output, if possible. However, when I interrogate the collection in an override of OnPreRender, the control in the template looks like this in the debugger:
{System.Web.UI.DataBoundLiteralControl}
System.Web.UI.DataBoundLiteralControl: {System.Web.UI.DataBoundLiteralControl}
AppRelativeTemplateSourceDirectory: "~/"
BindingContainer: {MyControls.MyControlData}
ClientID: "MyControl1_ctl01_ctl00"
Controls: {System.Web.UI.EmptyControlCollection}
EnableTheming: True
EnableViewState: True
ID: "ctl00"
NamingContainer: {MyControls.MyControlData}
Page: {ASP.default_aspx}
Parent: {MyControls.MyControlData}
Site: Nothing
SkinID: ""
TemplateControl: {ASP.default_aspx}
TemplateSourceDirectory: "/MyControls"
UniqueID: "MyControl1$ctl01$ctl00"
Visible: True
As you can see the "ml_errormessage" value is nowhere to be found. Upon analysis of the DataBind event of the Control class using Reflector, I see that it delegates the binding behavior to each control. In other words, each control handles its own databinding. However, since I have no way of knowing in advance what control types will be in the template, how can this change be done?
Note: an acceptable alternative would be to add a new HtmlGenericControl (span) in the exact spot where the "ml_errormessage" is and add it as a class to this new control.
On a side note, is there an easy way to get the control's output to indent for easy reading during debugging?