Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Panel Curve Container - An ASP.NET Custom Control Nugget

4.79/5 (22 votes)
15 Nov 2005CPOL3 min read 1   3.4K  
An ASP.NET custom panel control which is curved on the corners, could be minimized/maximized, displayed as a nugget, and can work as a container for anything.

Image 1

Introduction

I wanted to have a control which could work as a container and be used similar to System.Web.UI.WebControls.Panel <ASP:PANEL>, which is curved at corners and at the same time has its own custom header text.

Process

I searched the internet a lot to find a control similar to the Panel control but never got any help. So I decided to make one on my own. One way to do this was to create a user control which forms the curve and ask the developer to pass the values to this control, which was making the entire process too complex (creating too many user controls was a tedious job and would be difficult to manage), at the same time, I didn't want to place every code of mine inside a user control just for the sake of forming boundaries. Finally, one of the MSDN examples talked about such an implementation, but then it also had a flaw, it would throw an error if the control is used inside a user control or a DataGrid because the IDs are prefixed to the child control in this case. Then, I created my own control and tested it successfully inside a user control, a DataGrid, a nested DataGrid, and in many other ways, and it always worked.

Features

The following features are available for this control:

  • Curved tab header
  • Minimize icon to minimize the tab
  • Print icon to print the selected nugget
  • You can customize the header text displayed in the header
  • You can change the background color of the top tab or the bottom body
  • You can use a user control, custom control or any web control inside the container and still you can access those controls directly in your code-behind

    In the code-behind:

    C#
    protected TextBox txt;

    In the aspx:

    HTML
    <Tittle:PanelCurveControl ...>
    <asp:textbox id=txt ... /> 
    </Tittle:PanelCurveControl>
  • This control will maintain its minimize/maximize state during postback.
  • This control can be used inside a DataGrid or a User Control (where the IDs of the parent control are prefixed to that of the child control), without any issue.

How to Use It

If you have ever used <asp:panel>, then you can use this custom control as well:

HTML
<Tittle:PanelCurveControl ID=
 "Panelcurvecontrol1" runat="server" Title="My first Panel" >
    Name:<br>
       <asp:textbox id=txt runat=server />            
</Tittle:PanelCurveControl>

The above would be rendered as:

Image 2

Attributes

  • Expandable: Makes the control expandable on demand. Default: true.
  • RenderInBox: Renders the contents in the box. Default false (used only if Expandable is false). Making Expandable true makes the tab disappear, but if Expandable is false:
    • RenderInBox being "true" shows the border of the container
    • RenderInBox being "false" shows no borders
  • Closed: Whether the contents of the expandable panel must be visible
  • Title: The text displayed as the caption of the expandable panel
  • Margin: Margin to use if the panel is expandable
  • HasMinimize: Whether to show minimize icon on screen or not
  • HasPrint: Whether to show Print icon on screen or not
  • DefaultMinimize: Render it minimized by default or not
  • BodyBackColor: Content back color
  • TabBackColor: Top tab back color
  • HeaderTextColor: Top header text color

Some Technical Details

I've inherited this control from ASP:Panel so that it can be used in the same manner as Panel. I have not deliberately inherited it from INamingContainer, and the reason behind this is that I didn't want it to prefix the parent ID before every child control ID (it gives a problem if the control is used inside a grid or a user control). A hidden field is used which retains its minimize/maximize state during postbacks. I fixed a hidden field ID so that it maintains the state in a normal page and inside any control.

C#
if ( this.UniqueID.IndexOf(":") >=0 )
    hdn.ID = this.ID + "_hdnMinimizeState"; 
    //Within some user control or grid 
    //E.g. client id will be in this case 
    //"UserControl1__ctl0_tblCrvPnlControl2_hdnMinimizeState"
else
    hdn.ID = this.UniqueID + "_hdnMinimizeState"; 
    //Straight on aspx page, 
    //E.g. client id will be in this case 
    //"tblCrvPnlControl1_hdnMinimizeState"

PanelCurveControl.cs:

C#
using System;
using System.ComponentModel;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.IO;
using System.Collections.Specialized;

[assembly: TagPrefix ("Tittle.Controls" , "Tittle") ]
namespace Tittle.Controls
{    
    #region Table Curve Panel Control (Expandable)
    /// <summary>
    /// Renders a tab control on page. i.e. A tabbed 
    /// image on top of the table and you can have ur own 
    /// contents in between that.
    /// <example>
    /// <code>
    /// <Tittle:PanelCurveControl runat="server" 
    /// Expandable="true" 
    /// Width="500px"
    /// Margin="10"
    /// Title="Employees">
    ///        <table border=1>
    ///        <tr><td>test1</td><td>test2</td></tr>
    ///        <tr><td>test3</td><td>test4</td></tr>
    ///        </table>
    /// </Tittle:PanelCurveControl>    
    /// </CODE>
    /// </EXAMPLE>
    /// <AUTHOR>Tittle Joseph (tittlejoseph@yahoo.com) India.</AUTHOR>
    /// <URL>http://www.codeproject.com/PanelCurveContainer/</URL>
    /// </SUMMARY>
    [ToolboxData(
     "<{0}:PanelCurveControl runat=
        server Expandable='true' id='tblCrvPnl' Width='200px'>")]
    public class PanelCurveControl : Panel, IPostBackDataHandler 
    {
        private string skinName             = ""; //"/BasicNuggetSkin"; 
        private bool hasMinimize            = true;
        private bool hasPrint               = true;        
        private string imgPath;
        private Color bodyBackColor = Color.Transparent;
        private string tabBackColor = "#99CCFF";
        private string headerTextColor = "black";
        
        public PanelCurveControl() : base()
        {            
           Expandable = true;
           RenderInBox = false;
           Title = "Panel";
           Font.Name = "verdana";
           Font.Size = FontUnit.Point(10);
           Margin = 2;
           Closed = false;                        
           ForeColor = Color.Black;
           BorderColor = Color.DodgerBlue;            
           imgPath = 
             HttpContext.Current.Request.ApplicationPath + 
                                     skinName + "/Images/";
           //imgPath = "/Images/";
        }
        
        /// <SUMMARY>
        /// Makes the control expandable on demand,  
        /// Default: true
        /// </SUMMARY>
        [Browsable(true),
        Category("Validation"),
        DefaultValue("true"),
        Description ("Makes the control expandable on demand.") ] 
        public bool Expandable
        {
           get {return Convert.ToBoolean(ViewState["Expandable"]);}
           set {ViewState["Expandable"] = value;}
        }        

        /// <SUMMARY>
        /// Render the contents in the box 
        /// (used only if Expandable is false),
        /// 
        /// Expandable true makes tab disappear, 
        /// but if Expandable is false 
        ///        RenderInBox is "true" shows border of container.
        ///        RenderInBox is "false" no border appears.
        /// Default: false
        /// </SUMMARY>
        [Browsable(true),
        Category("Misc"),
        DefaultValue("false"),
        Description ("Render the contents in the box.") ]
        public bool RenderInBox
        {
            get {return Convert.ToBoolean(ViewState["RenderInBox"]);}
            set {ViewState["RenderInBox"] = value;}
        }
        
        /// <SUMMARY>
        /// Whether the contents of the expandable panel must be visible 
        /// Equivalent to "DefaultMinimize" attribute
        /// Default: false
        /// </SUMMARY>
        [Browsable(true),
        Category("Validation"),
        DefaultValue("false"),
        Description ("Whether the contents of the " + 
                 "expandable panel must be visible.") ] 
        public bool Closed
        {
            get {return Convert.ToBoolean(ViewState["Closed"]);}
            set {ViewState["Closed"] = value;}
        }        
        
        /// <SUMMARY>
        /// The text displayed as the caption of the expandable panel 
        /// 
        /// Default: "Panel"
        /// </SUMMARY>
        [Browsable(true),
        Category("Behavior"),
        DefaultValue("Panel"),
        Description ("The text displayed as the " + 
              "caption of the expandable panel.") ]
        public string Title
        {
           get {return Convert.ToString(ViewState["Title"]);}
           set {ViewState["Title"] = value;}
        }
        
        /// <SUMMARY>
        /// The margin to use if the panel is expandable 
        ///
        /// Default: "2"
        /// </SUMMARY>
        [Browsable(true),
        Category("Appearance"),
        DefaultValue("2"),
        Description ("Margin to use if the panel is expandable.") ]
        public int Margin
        {
           get {return Convert.ToInt32(ViewState["Margin"]);}
           set {ViewState["Margin"] = value;}
        }        

        /// <SUMMARY>
        /// SkinName to be used in nugget i.e. "BasicNuggetSkin", 
        /// "BillInfoNuggetSkin", "DataGridNuggetSkin", 
        /// "TabbedNuggetSkin"
        /// 
        /// Default is "BasicNuggetSkin"
        /// </SUMMARY>
        [Browsable(true),
        Category("Behavior"),
        DefaultValue("BasicNuggetSkin"),
        Description ("Skinname to be used in nugget.") ]
        public string SkinName
        {
            get{ return skinName;}
            set{ skinName = value;}
        }
        
        /// <SUMMARY>
        /// Whether to show Minimize icon on screen or not.
        /// 
        /// Default: true
        /// </SUMMARY>
        [Browsable(true),
        Category("Validation"),
        DefaultValue("true"),
        Description ("Whether to show minimize " + 
                          "icon on screen or not.") ]
        public bool HasMinimize
        {
            get{ return hasMinimize;}
            set{ hasMinimize = value;}
        }
        
        /// <SUMMARY>
        /// Whether to show Print icon on screen or not.
        /// 
        /// Default: true
        /// </SUMMARY>
        [Browsable(true),
        Category("Validation"),
        DefaultValue("true"),
        Description ("Whether to show Print " + 
                      "icon on screen or not.") ]
        public bool HasPrint
        {
            get{ return hasPrint;}
            set{ hasPrint = value;}            
        }
        
        /// <SUMMARY>
        /// Render it minmized by default or not
        /// 
        /// Default: false
        /// </SUMMARY>
        [Browsable(true),
        Category("Appearance"),
        DefaultValue("false"),
        Description ("Render it minimized by default or not.") ]
        public bool DefaultMinimize
        {
            get{ return Closed;}
            set{ Closed = value;}
        }

        /// <SUMMARY>
        /// Content Back Color
        /// </SUMMARY>
        public Color BodyBackColor
        {
            get { return bodyBackColor; }
            set { bodyBackColor = value; }
        }

        /// <SUMMARY>
        /// Top Tab Back Color
        /// </SUMMARY>
        public string TabBackColor
        {
            get { return tabBackColor; }
            set { tabBackColor = value; }
        }

        /// <SUMMARY>
        /// Top Header Text Color
        /// </SUMMARY>
        public string HeaderTextColor
        {
            get { return headerTextColor; }
            set { headerTextColor = value; }
        }

        /// <SUMMARY>
        ///RaisePostDataChangedEvent::LoadPostData
        /// Automatically updates the Closed property based on the content
        /// of hidden field named as this control 
        /// </SUMMARY>
        /// <PARAM name="postDataKey"</PARAM>
        /// <PARAM name="postCollection"></PARAM>
        /// <RETURNS></RETURNS>
        public virtual bool LoadPostData(string postDataKey, 
                          NameValueCollection postCollection) 
        {
            bool currentValueOfClosed = Closed;
            bool postedValueOfClosed = 
              Convert.ToBoolean(postCollection[postDataKey+
                                       "_hdnMinimizeState"]);

            // What if the field is empty?
            if (!currentValueOfClosed.Equals(postedValueOfClosed)) 
            {
                Closed = postedValueOfClosed;
                return true;
            }

            return false;
        }                
        
        /// <SUMMARY>
        /// IPostBackDataHandler::RaisePostDataChangedEvent 
        /// </SUMMARY>
        public virtual void RaisePostDataChangedEvent() 
        {
            // Do nothing here
            // No need of firing server-side events
        }        
        
        /// <SUMMARY>
        /// Fires when the panel gets loaded
        /// </SUMMARY>
        /// <PARAM name="e"></PARAM>
        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);            

            // Check the browser caps and disable collapse/expand if needed
            bool uplevel = false;
            HttpBrowserCapabilities caps = Page.Request.Browser;
            if (caps.Browser.ToUpper().IndexOf("IE") > -1)
            {
                // This is IE. But is it at least v5?
                if (caps.MajorVersion >4)
                    uplevel = true;
            }

            // If the browser is not IE5 or higher, drop collapse/expand 
            if (!uplevel)
            {
                Expandable = false;
                RenderInBox = true;
            }

            //Need to write this, so that LoadPostData() gets called.
            Page.RegisterRequiresPostBack(this);
        }

        /// <SUMMARY>
        /// Render the control
        /// </SUMMARY>
        /// <PARAM name="output"></PARAM>
        protected override void Render(HtmlTextWriter output)        
        {
            if (!Expandable)
            {
                if (!RenderInBox)
                    base.Render(output);
                else
                    RenderContentsInBox(output);
                return;
            }

            // Add margin information if the panel is expandable
            Style["margin"] = Margin.ToString();
            Style["display"] = (Closed ?"none" :"");
        
            // The internal panel must cover 100% of the parent area
            // irrespective of the physical width. We change this here
            // so that the original Panel code doesn't reflect the
            // external width.
            Unit oldWidth = Width;
            Width = Unit.Percentage(100);
            
            //Add Hidden Field to maintain 
            //minimize/maximize state of the curve.
            TextBox hdn = new TextBox();
            hdn.Attributes.Add("style","display:none");
            //This is what created a big nuisance to me
            if ( this.UniqueID.IndexOf(":") >=0 )
                hdn.ID = this.ID + "_hdnMinimizeState"; 
            //"UserControl1__ctl0_tblCrvPnlControl2_hdnMinimizeState"
            else
                hdn.ID = this.UniqueID + "_hdnMinimizeState"; 
            //"tblCrvPnlControl1_hdnMinimizeState"
            
            hdn.Text = Closed.ToString();
            this.Controls.Add(hdn);

            // Capture the default output of the Panel
            StringWriter writer = new StringWriter();
            HtmlTextWriter buffer = new HtmlTextWriter(writer);
            base.Render(buffer);
            string panelOutput = writer.ToString();

            // Restore the wanted width because this affects the outer table
            Width = oldWidth;
            BuildControlTree(output, this.ClientID, panelOutput);
            return;
        }                
        
        // Handle the PreRender event        
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);

            CreateClientScript();
        }
        
        /// <SUMMARY>
        /// Build the markup for this custom Panel control
        /// </SUMMARY>
        /// <PARAM name="output"></PARAM>
        /// <PARAM name="id"></PARAM>
        /// <PARAM name="panelOutput"></PARAM>
        private void BuildControlTree(HtmlTextWriter output, 
                               string id, string panelOutput)
        {                        
            Table t = new Table();
            //t.ID = "thePanel";            
            t.ID = id + "_thePanel";
            t.CellPadding = 0;
            t.CellSpacing = 0;            
            t.Width = Unit.Percentage(100); //Width;
            t.HorizontalAlign = HorizontalAlign.Center;
            t.Style.Add("margin", "0 0 0 0px");                        

            // Prepare the topmost row
            TableRow rowTop = new TableRow();
            
            // Leftmost cell
            TableCell leftCell = new TableCell();            
            leftCell.HorizontalAlign = HorizontalAlign.Left;
            leftCell.Style.Add("width","10px");        
            leftCell.Style.Add("background",
             tabBackColor + " url(" + imgPath + 
              "topleft.gif) top left no-repeat");
            leftCell.Text = " ";
            rowTop.Cells.Add(leftCell);            
            
            //Label Info
            TableCell centerCell = new TableCell();
            centerCell.Style.Add("background-Color",tabBackColor);
            centerCell.Wrap = false;
            centerCell.Attributes.Add("onselectstart","return false"); 
            //Not allowing user to select Tab Title text 
            //through mouse or double click.
            if ( hasMinimize == true )
              centerCell.Attributes.Add("ondblclick",
              String.Format("javascript:MinMaxTableCurvePanel('{0}')", id));
            Literal lit = new Literal();
            lit.Text = String.Format("{0}",Title,headerTextColor);
            centerCell.Controls.Add(lit);                    
            rowTop.Cells.Add(centerCell);

            //Print Icon Cell
            if ( hasPrint )
            {
                TableCell printCell = new TableCell();
                //printCell.HorizontalAlign = HorizontalAlign.Right;
                printCell.Style.Add("background-Color",tabBackColor);
                printCell.Wrap = false;
                printCell.Width = Unit.Pixel(20);
                System.Web.UI.WebControls.Image imgPrint = 
                       new System.Web.UI.WebControls.Image();
                imgPrint.AlternateText = "Print View";
                imgPrint.BorderWidth = 0;
                imgPrint.Style.Add("cursor","hand");
                imgPrint.Attributes.Add("onclick",
                 String.Format("javascript:PrintTableCurvePanel('{0}')",id));
                imgPrint.ImageAlign = ImageAlign.AbsMiddle;
                imgPrint.ImageUrl = imgPath + "print.gif";
                printCell.Controls.Add(imgPrint);
                rowTop.Cells.Add(printCell);
            }
            
            //Minimize/Maximize Icon Cell
            if ( hasMinimize )
            {
                TableCell minimizeCell = new TableCell();
                //minimizeCell.HorizontalAlign = HorizontalAlign.Right;
                minimizeCell.Style.Add("background-Color",tabBackColor);
                minimizeCell.Wrap = false;
                minimizeCell.Width = Unit.Pixel(20);
                System.Web.UI.WebControls.Image imgMinimize = 
                         new System.Web.UI.WebControls.Image();
                //imgMinimize.ID = "img";
                imgMinimize.ID = id + "_imgPlusMinus";
                imgMinimize.AlternateText = "Minimize/Maximize the Panel";
                imgMinimize.BorderWidth = 0;
                imgMinimize.Style.Add("cursor","hand");
                imgMinimize.Attributes.Add("onclick",
                 String.Format("javascript:MinMaxTableCurvePanel('{0}')",id));
                imgMinimize.ImageAlign = ImageAlign.AbsMiddle;
                imgMinimize.ImageUrl = 
                  imgPath + (Closed==true?"plus.gif":"minus.gif");
                minimizeCell.Controls.Add(imgMinimize);
                rowTop.Cells.Add(minimizeCell);
            }

            // Right most cell
            TableCell rightCell = new TableCell();           
            rightCell.HorizontalAlign = HorizontalAlign.Right;
            rightCell.Width = Unit.Pixel(10);
            rightCell.Style.Add("width","10px");     
            rightCell.Style.Add("background",tabBackColor + 
              " url(" + imgPath + "topright.gif) top right no-repeat");
            rightCell.Text = " ";            
            rowTop.Cells.Add(rightCell);

            // Add the top row to the table
            t.Rows.Add(rowTop);

            int colspan = 3;
            if ( hasPrint )
                colspan++;
            if ( hasMinimize )
                colspan++;

            // Insert the Panel's markup in the table cell  {Container}
            TableRow rowBody = new TableRow();
            if ( bodyBackColor != Color.Transparent  )
            rowBody.BackColor = bodyBackColor;
            TableCell cellBody = new TableCell();            
            cellBody.ColumnSpan = colspan;
            cellBody.Text = panelOutput;
            cellBody.Style.Add("BORDER","#cccccc 1px solid");
            cellBody.Style.Add("padding","0 0 0 0px"); //"0 5 5 5px"
            cellBody.Style.Add("margin","0 0 0 0px"); //"0 0 5 0px"

            rowBody.Cells.Add(cellBody);
            t.Rows.Add(rowBody);

            // Output
            t.RenderControl(output);
        }        
        
        /// <SUMMARY>
        /// Add client side scripting
        /// </SUMMARY>
        private void CreateClientScript()
        {
          string jscript = @"
           <style>                            
             P.PanelCurveTitleStyle
             {
               font-family:verdana;
               font-size: 12px;
               font-weight : bold;
               text-align: center;    
             }
           </STYLE>                        
          <script language=javascript>
            var imgPath='" + imgPath + @"'; 
          </script>
          <script language=javascript>   
           function MinMaxTableCurvePanel(cntrlId)
           {
             //Get state from hidden control.
             var closed_TableCurvePanel = 
               document.getElementById(cntrlId+'_hdnMinimizeState').value;
             if ( closed_TableCurvePanel.toLowerCase() == 'true' )
             {
               document.getElementById(cntrlId).style.display = '';
               document.getElementById(cntrlId+'_hdnMinimizeState').value=
                                                                 false;
               document.getElementById(cntrlId+'_imgPlusMinus').src = 
                                                 imgPath + 'minus.gif';
             }
             else 
             {
               document.getElementById(cntrlId).style.display = 'none';
               document.getElementById(cntrlId+'_hdnMinimizeState').value = 
                                                                      true;
               document.getElementById(cntrlId+'_imgPlusMinus').src = 
                                                        imgPath + 'plus.gif';
             }
           }
           //TODO: this could be improved further to show tab on new window.
           function PrintTableCurvePanel(cntrlId)
           {                            
             var objDiv = document.getElementById(cntrlId);
             var winTableCurvePanel = 
                window.open('','winTableCurvePanelId','');
             winTableCurvePanel.document.write('
               <html><head></head><body onload=
                                  \'javascript:window.print()\'>');
             winTableCurvePanel.document.write(objDiv.innerHTML);
             winTableCurvePanel.document.write('</body></html>');
             winTableCurvePanel.focus();
           }
          </script>
         ";

         if (!Page.IsClientScriptBlockRegistered("TableCurvePanel_Script"))
          Page.RegisterClientScriptBlock("TableCurvePanel_Script", 
                                                         jscript );
       }

       /// <SUMMARY>
       /// Render the panel in a box (MSDN like)
       /// </SUMMARY>
       /// <PARAM name="output"></PARAM>
       private void RenderContentsInBox(HtmlTextWriter output)
       {
           this.Style.Add("BORDER","#cccccc 1px solid");
           this.Style.Add("padding","0 0 0 0px"); //"0 5 5 5px"
           this.Style.Add("margin","0 0 0 0px"); //"0 0 5 0px"
            base.Render(output);
       }
    }
    #endregion
}

ASPX code of the image displayed at the top:

ASP.NET
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" 
       AutoEventWireup="false" Inherits="PanelCurveContainer.WebForm1" %>
<%@Register TagPrefix="Tittle" namespace="Tittle.Controls" 
                               Assembly="ClassLibrary1" %>
<%@Register TagPrefix="Tittle" TagName=
   "WebUserControl" Src="WebUserControl1.ascx" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
 <head>
    <title>WebForm1</title>
 </head>
 <body MS_POSITIONING="GridLayout">
   <form id="Form1" method="post" runat="server">
     <Tittle:PanelCurveControl ID="Panelcurvecontrol1" 
       runat="server" Expandable="true" Margin="10" 
       Title="Panel Curve - Custom Tab Color" 
       TabBackColor="#FF9933">               
       <table width=90% align=center><tr>
       <td><font size=-1>Name:</font> 
       <asp:textbox id="Textbox1" runat=server /> </td>
       <td><font size=-1>Age:</font> 
       <input type=text /></td>
       </tr></table> </font>
     </Tittle:PanelCurveControl>
     <br>
     <Tittle:PanelCurveControl ID="Panelcurvecontrol2" 
       runat="server" Expandable="true" 
       Title="Panel Curve - Custom Header Text Color and Content Back Color"
       BodyBackColor="Pink" HeaderTextColor="#009900">
        Content here
     </Tittle:PanelCurveControl>
     <br>           
       <table width="95%" border=0 align=center>
        <tr>
          <td valign=top>
            <Tittle:PanelCurveControl ID="Panelcurvecontrol3" 
              runat="server" Expandable="true" 
              Title="Panel Curve - Without Print Icon"
              HasPrint="False" BodyBackColor="#CCFFFF" >
               Name:<br>
              <asp:textbox id=txt runat=server /> 
             </Tittle:PanelCurveControl>
             <br>
             <Tittle:PanelCurveControl ID="Panelcurvecontrol4" 
                 runat="server" Expandable="true" 
                 Title="Panel Curve - Without Any Icon" 
                 HasPrint="False" HasMinimize="false" 
                 HeaderTextColor="#009900" TabBackColor="#FFCC99">
               Content here
             </Tittle:PanelCurveControl>
          </td>
          <td valign=top>
            <Tittle:PanelCurveControl ID="Panelcurvecontrol5" 
                runat="server" Expandable="true" 
                Title="Panel Curve - Master Curve" 
                HasMinimize="false" HasPrint="false" 
                HeaderTextColor="pink" TabBackColor="green" >
              More Panels
              <table width="100%">
                <tr>                           
                  <td valign=top >
                     <Tittle:PanelCurveControl ID="Panelcurvecontrol7" 
                         runat="server" Expandable="true" 
                         Title="Panel Curve - Master Curve - Child 1" 
                         HasMinimize="false" HasPrint="false" 
                         HeaderTextColor="#666600" TabBackColor="#CCFFCC" >
                        One More Child
                        <Tittle:PanelCurveControl ID="Panelcurvecontrol8" 
                          runat="server" Expandable="true" 
                          Title="Panel Curve - Master Curve - Child 1 - Child 1"
                          HasPrint="false" HeaderTextColor="white" 
                          TabBackColor="#336699" >
                        Content here   
                        </Tittle:PanelCurveControl>
                     </Tittle:PanelCurveControl>
                  </td>
                </tr>
              </table>
           </Tittle:PanelCurveControl>
         </td></tr>
       </table>           
       <tittle:WebUserControl id="WebUserControl1" runat="server" />
       <br><br>
       <br>
    </form>
 </body>
</html>

Conclusion

I would really be interested in knowing if this code has helped you by any means, please do not hesitate or be lazy in dropping your comments telling what you have felt about this submission and how much it has helped you. I would appreciate it if you keep the URL of this page inside the control's code while using it.

History

  • 15th November, 2005: Created

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)