Customizing the rendering of the UpdatePanel

Over the past few months I've received some feedback that there need to be more ways to customize the rendering of the UpdatePanel control. The response I gave was that we felt that using <div> and <span> would cover by far most scenarios. The one thing I would have loved to add to UpdatePanel is at least a CssClass property, but there are some workarounds to it, so we ended up not adding it.

To satisfy the demands of at least some of you, I've written a custom UpdatePanel that supports using arbitrary tags for the rendering as well as a new CssClass property.

namespace LeftSlipper {
    using System;
    using System.ComponentModel;
    using System.Web.UI;
    using Microsoft.Web.UI;

    public class CustomUpdatePanel : UpdatePanel {
        private string _cssClass;
        private HtmlTextWriterTag _tag = HtmlTextWriterTag.Div;

        [DefaultValue("")]
        [Description("Applies a CSS style to the panel.")]
        public string CssClass {
            get {
                return _cssClass ?? String.Empty;
            }
            set {
                _cssClass = value;
            }
        }

        // Hide the base class's RenderMode property since we don't use it
        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public new UpdatePanelRenderMode RenderMode {
            get {
                return base.RenderMode;
            }
            set {
                base.RenderMode = value;
            }
        }

        [DefaultValue(HtmlTextWriterTag.Div)]
        [Description("The tag to render for the panel.")]
        public HtmlTextWriterTag Tag {
            get {
                return _tag;
            }
            set {
                _tag = value;
            }
        }

        protected override void RenderChildren(HtmlTextWriter writer) {
            if (IsInPartialRendering) {
                // If the UpdatePanel is rendering in "partial" mode that means
                // it's the top-level UpdatePanel in this part of the page, so
                // it doesn't render its outer tag. We just delegate to the base
                // class to do all the work.
                base.RenderChildren(writer);
            }
            else {
                // If we're rendering in normal HTML mode we do all the new custom
                // rendering. We then go render our children, which is what the
                // normal control's behavior is.
                writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
                if (CssClass.Length > 0) {
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
                }
                writer.RenderBeginTag(Tag);
                foreach (Control child in Controls) {
                    child.RenderControl(writer);
                }
                writer.RenderEndTag();
            }
        }
    }
}

Here's the markup I used in my page (along with a fancy CSS rule):

<%@ Register Namespace="LeftSlipper" TagPrefix="ls" %>
...
<ls:CustomUpdatePanel runat="server" ID="CustomUpdatePanel1"
   
CssClass="greenPanel" Tag="B">
    <ContentTemplate>
        <asp:Label ID="Label1" runat="server"></asp:Label>
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </ContentTemplate>
</ls:CustomUpdatePanel>

ls:CustomUpdatePanel runat="server" ID="CustomUpdatePanel1"
   
CssClass="greenPanel" Tag="B">
    <ContentTemplate>
        <asp:Label ID="Label1" runat="server"></asp:Label>
        <asp:Button ID="Button1" runat="server" Text="Button" />
    </ContentTemplate>
</ls:CustomUpdatePanel>

And here's what got rendered with these settings (actual times may vary!):

<b id="CustomUpdatePanel1" class="greenPanel">
    <span id="Label1">12/6/2006 9:18:07 PM</span>
    <input type="submit" name="Button1" value="Button" id="Button1" />
</b>

As usual, feedback is welcome, or just enjoy the control!

Technorati Profile

10 Comments

  • Thanks!

    I have a different unrelated question, though.
    Why is the CssClass not backed up by a ViewState?

    Edmund

  • Edmund,
    There's no particular reason the CssClass property isn't stored in ViewState. It should be easy enough to modify the control to do that. However, one thing to consider is that if the UpdatePanel is the outer-most one being updated, it's outer HTML isn't updated.
    Because of this, if the UpdatePanel "IsInPartialRendering" you'd have to output some script or use ScriptManager.RegisterDataItem() to send down the new CSS class to the client to be updated.
    Perhaps I'll cover this in another blog post.
    - Eilon

  • How can I change the output stream in Page.Render() that has an UpdatePanel in an incremental refresh?

  • You did manage to modify the childs of the panel, but what if you were to change the OUTSIDE of the panel?

    Like adding a header to the update panel in a div.

    Overriding the Render method could be a good start?

  • Sorry for the stupid question. I'm at a new job coming from ColdFusion into ASP.Net. This looks like a very useful tag, but how do I create it? I tried creating a C# class containing this code, which built fine, but my .aspx file won't build because it can't see this object, even with the @Register command at the top.

  • Nick:
    What error are you getting? And where did you place the C# class? If you created a "Web Site" project the code file should be in the App_Code folder. If it's in a "Web Application" project you should be able to place the code file anywhere in the project.

    Thanks,
    Eilon

  • Hi Nick,
    As this sample was written before ASP.NET AJAX was released, it's using the old namespace. Everything that was Microsoft.* is now System.*. So, instead of "using Microsoft.Web.UI", you should do "using System.Web.UI" (which is already there anyway).

    Thanks,
    Eilon

  • This doesn't work. Try with more complex inner controls.

  • Works like a charm, thanks!

  • I had problems getting this working until I added the name of the project's own assembly into the Register line at the top of my aspx:



    My project outputs GroupMembers.dll - any idea why this was necessary

Comments have been disabled for this content.