views:

575

answers:

2

I need to use objChildControl.RenderControl or objControl.RenderChildren to manually render my child controls. But it looks like these methods are incomplete.

All my child controls use the OnPreRender event to register clientscript and client stylesheets (since these can only be created in the prerender event).

I have 2 main issues, passing the current System.Web.UI.Page object to a child control and making sure the OnPreRender event is fired on these child controls.

It seems that I can't use the RenderControl method on my child controls since the OnPreRender event will not be called. I can however pass the Page object by objChildControl.Page = Me.Page

When I use RenderChildren I cannot pass the Page object, or can I? And i'm not sure if the OnPreRender event is even called when I use RenderChildren.

Some help would be appreciated, since i'm stuck ;)

Update

I found a way to get the result I need, but it is not the solution I want. Example:

Code I want:

<wc:ParentControl id="objParent" runat="server" bla="etc">
<Content> <!-- This is an InnerProperty of the ParentControl --><DIV>bla bla bla bla.....<wc:SomeControl id="objSomeControl" runat="server" /><wc:3rdPartyControl id="obj3rdPartyControl" runat="server" /></DIV></Content>
</wc:ParentControl>

CodeBehind: objParentControl.Content.RenderControl(Writer)

And then the issues mentioned above will begin. How to make sure that for all the children within Content the OnPreRender will be called?

Code which does work (but then the RenderControl method is just useless):

<wc:ParentControl id="objParentControl" runat="server"></wc:ParentControl>
<wc:Content id="objContent" runat="server"><DIV>bla bla bla bla.....<wc:SomeControl id="objSomeControl" runat="server" /><wc:3rdPartyControl id="obj3rdPartyControl" runat="server" /></DIV></wc:Content>

Then just use the RenderBeginTag and RenderEndTag of the wc:Content control. Then the OnPreRender event is called. But I wan't to embed the content into the parentcontrol by using an InnerProperty. And then manually rendering the childcontrols by RenderControl or RenderChildren.

A: 

msdn describes the life-cycle in detail (there's also a nice walkthrough)

some code would be nice to help you!

edit:
following example (in c#) for registering clientscripts and stylesheets:

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    var pathCssFile = this.Page.ResolveUrl(fooStyleUri);
    if (!this.Page.Header.Controls.OfType<HtmlLink>().Any(link => string.Equals(link.Href, pathCssFile)))
    {
     var cssLink = new HtmlLink();
     cssLink.Attributes.Add("href", pathCssFile);
     cssLink.Attributes.Add("type", "text/css");
     cssLink.Attributes.Add("rel", "stylesheet");
     this.Page.Header.Controls.Add(cssLink);
    }

    if (!this.Page.ClientScript.IsClientScriptIncludeRegistered(fooScriptKey))
    {
     this.Page.ClientScript.RegisterClientScriptInclude(fooScriptKey, this.Page.ResolveClientUrl(fooScriptUri));
    }
}
Andreas Niedermair
Thank you for you reply.I read this on the MSDN article:The PreRender event occurs for each control on the page. Use the event to make final changes to the contents of the page or its controls.Well thank you Microsoft, I am sure it will all work if it follows the normal page flow. But now the situation is different. I'm taking over the page flow, because I manually render my child controls.Maybe If I won't do stuff manually, and I would override RenderBeginTag and RenderEndTag to write a <DIV>childcontrols</DIV> it will work. But why offer me the RenderControl method then MS!
Erik
Thank you for the code. But that's not my problem.I have a public method on all my controls, called RegisterClientResources, which I can use to manually register the resources.I cannot use Page code either (OnLoad) is must all be written in the webcontrol. We should focus on the question about how we can make sure that rendering a child control manually will fire the onPreRender event.And why I can't register resources manually for each control in this context: Because there might be 3rd party child controls involved. I dont know what child controls are placed in my control.
Erik
A: 

I had a similar issue. I'm not sure if it's the same issue you're experiencing, but the problem I was having was that I had a ParseChildren(true) attribute on my container control. Because ParseChildren was true, the child controls would be put into a property, rather than into the containing control's child controls collection, and would never get their OnPreRender function called.

I ended up overriding the CreateChildControls function in my containing control class, where I added everything from my parsed collection to the Controls collection. Because I'm overriding the Render function anyway, I don't worry about the controls in the Controls collection being rendered when I didn't want them to be.

Something like below:

[ParseChildren(true, "MyKids")]
public class Example : Control {

 private ArrayList _kids = new ArrayList();

 public ArrayList MyKids {
  get { return _kids; }
  set { _kids = value; }
 }

 protected override CreateChildControls() {
  Controls.Clear();
  foreach(Control c in _kids)
   Controls.Add(c);
 }

 protected override Render(HtmlTextWriter writer) {
  ...
 }
}
mrdrbob