blog community

Welcome to blog community Sign in | Join | Help
in Search

Wouter van Vugt

This blog is no longer maintained and has moved

Doing it myself, a WaitPanel

After reading Danny Chen's challenge on building a WaitPanel, I decided to try and do it myself. Mainly because the article pointed to in this post, doesn't work as expected.

When examining the problem, you quickly find that the WaitPanel needs to render itself in part (Render Phase), before allowing it's child controls to enter the Page Lifecycle (the long action happens in the Load phase). I perform this act by customizing the ControlCollection.

Now beforehand, I must be honest. My solution isn't 100% perfect either, but I believe that is impossible using normal WebControls. My solution will bug if you use controls such as a GridView inside the WaitPanel. This happens because the Page Lifecycle has entered the Render phase, and on that time a child GridView still needs to go through Init/Load/PreRender (because it isn't added yet to a ControlCollection). The GridView uses Page.RegisterRequiresViewStateEncryption, which you may not call after PreRender (we're really in Render remember?). Hence it bugs. But given the problem definition, any WebControl based solution will likely have this same problem.

Now for some code. Two classes are used, one custom ControlCollection, and a Panel class.

public class WaitPanelControlCollection : ControlCollection

{

    List<Control> _lateChildren = new List<Control>();

 

    public WaitPanelControlCollection(Control owner)

        : base(owner)

    {

    }

 

    public override void Add(Control child)

    {

        _lateChildren.Add(child);

    }

 

    public void Flush()

    {

        foreach (Control ctrl in _lateChildren)

        {

            base.Add(ctrl);

        }

    }

}

Easy one, now for the WaitPanel class itself. It does three things. Create the ControlCollection, render some clientscript for hiding the wait screen and render the panel and child controls.

[ParseChildren(false)]

[PersistChildren(true)]

public class WaitPanel : WebControl

{

    protected override ControlCollection CreateControlCollection()

    {

        return new WaitPanelControlCollection(this);

    }

 

    protected override void OnPreRender(EventArgs e)

    {

        if(Page.ClientScript.IsClientScriptBlockRegistered("WaitPanel") == false)

        {

            Page.ClientScript.RegisterClientScriptBlock(typeof(WaitPanel),

                "WaitPanel",

                    @"function HideWaitPanel(id)

                    {

                        var panel = document.getElementById(id);

                        panel.style.display = ""none"";

                    }",

                    true);

        }

        base.OnPreRender(e);

    }

 

    protected override void Render(HtmlTextWriter writer)

    {

        if (DesignMode == false)

        {

            // Send the waitpanel div to the client, letting him

            // see he's gotta wait.

            Page.Response.BufferOutput = true;

            Page.Response.Write("<div id='" + ClientID + "' style='width:100%;height:3em;background-color:green'>Lazy loading.....</div>");

            Page.Response.Flush();

            // Flush the child controls into the Controls collection

            // which causes them to catch up in the lifecycle.

            ((WaitPanelControlCollection)Controls).Flush();

            // Send some script to hide the waitpanel div again

            Page.Response.Write("<script>HideWaitPanel('" + ClientID + "')</script>");

        }

        base.RenderChildren(writer);

    }

}

 

Published Wednesday, March 01, 2006 9:32 AM by wouterv
Filed under:

Comments

No Comments
Anonymous comments are disabled

This Blog

Syndication

News


Add to Technorati Favorites
Powered by Community Server, by Telligent Systems