Click here to Skip to main content
Click here to Skip to main content

Panel Curve Container - An ASP.NET Custom Control Nugget

By , 15 Nov 2005
 

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 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 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:

    protected TextBox txt;

    In the aspx:

    <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:

<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:

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.

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

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:

<%@ 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

  • Created on: 15 Nov 2005.

License

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

About the Author

Tittle Joseph
Team Leader Royal Bank of Scotland
India India
Member
Total 11+ years of experience in Software Development. Expertise in .net (C#, asp.net, controls making, webservice, ado.net, xml/xsl, assemblies, rational XDE etc.) also UML, Design Patterns, ASP, Javascript, VbScript, Dhtml, CSS etc.
 
Member of Planet-Source-Code.com, www.brainbench.com and many other and have submitted several snippets/sample applications on the web.
 
Email:tittlejoseph@gmail.com

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNot compatible in Netscape/Mozillamemberjjsmitty26 May '06 - 9:30 
Hi Joseph,
 
I really liked your example and I started to use it and modify it heavily for one of my projects. However, I noticed it does not work in Netscape/Mozilla. The issue seems to be that the Framework will not render the tables and table cells that are dynamically added via code. In other words, all that gets rendered is the panel and the panel's "inner html". The tables supporting the tab and the content "box" are not rendered - not even added to the control's output. The only thing that ever gets rendered are the contents of the panelOutput.
 
I have never seen anything like that, but this is what is happening. Any ideas on how to efficiently get the rest of the control to render in Netscape/Mozilla?
 
Thanks,
 
J.
 
J Smith
Sr. Software Engineer
Lockheed Martin
GeneralRe: Not compatible in Netscape/MozillamemberTittle Joseph28 May '06 - 20:02 
Thanks Smith for liking it. Big Grin | :-D
 
I dont have Netscape to verify it, but i'm surprised how you getting error, becaues I'm using complete .net code, which should automatically render respective code as per browser.D'Oh! | :doh:
 
Please try to fix yourself and provide a summary here so that others could make use of that. Big Grin | :-D
 

 
---------
Tittle
GeneralRe: Not compatible in Netscape/Mozillamemberjostster20 Mar '09 - 5:56 
I concur that this does not work in firefox. Also in IE7 it does not have the curves.
GeneralRe: Not compatible in Netscape/Mozillamemberjostster20 Mar '09 - 7:09 
I meant to say in FF you can view the content but not the title and header.
AnswerRe: Not compatible in Netscape/Mozillamemberakanphade29 Jun '09 - 14:35 
Well I was just looking at this composite control and was I able to find the fix immediately!
 
In the page OnLoad function, joseph is trying to verify the IE version,less than IE version 5 makes the control not expandable!
 
Well I just made it true irrespective of the IE version. I just tested the results in FF and the control are coming along perfect with the desired functionality.
 
I have not tested this code with IE version < 5.
 
Here is the change!!!
 
if (!uplevel)
{
Expandable = true;
RenderInBox = true;
}
 

I hope this helps others!!! Smile | :)
 
Happy coding!
 
Amol

AnswerRe: Not compatible in Netscape/Mozillamemberakanphade29 Jun '09 - 14:59 
when IE version < 5, drop collapse/expand:
 
Here is the change;
 
if ((caps.Browser.ToUpper().IndexOf("IE") > -1)
&& (!uplevel))
{
Expandable = false;
RenderInBox = true;
}
 
Amol

QuestionJavaScript Errormemberdmichael26623 May '06 - 5:10 
First off, great control!   I absolutely love it and I know it will save me a lot of time in the future, so thank you.
 
The only problem is that (and I know this question was previously asked but I didn't see an answer) when I click on the minimize button I get a Javascript error "Object Required".   I looked at the Source View of the page and the problem is that for some reason "_thePanel" is getting appended to the end of the control's name.   So the control gets rendered as:
 
<table id="ctl00_ContentPlaceHolder1_pnlGeneral_thePanel"
 
but the javascript functions use an ID without the "_thePanel" appended as follows:
 
ondblclick="javascript:MinMaxTableCurvePanel('ctl00_ContentPlaceHolder1_pnlGeneral')"
 
I should say that I'm using the control inside the new "<asp:Content>" control in VS 2005.   Any help you might be able to provide would be great.
 
Devin
AnswerRe: JavaScript ErrormemberTittle Joseph23 May '06 - 21:03 
Hi,
 
First of all thanks for liking the control, hope it comes any help to you.
 
Everytime people who has got .net 2005 come to me and ask question, I wish I had .net 2005 with me and could rectify their problem D'Oh! | :doh: . The problem you talked really belong to .net 2005, microsoft might have changed/override some of their ID rendering technique OMG | :OMG: , because of which you are getting javascript error, and i'm unable to look into this as I dont have .net 2005. Either you wait till I fix this bug or please take some pain and try to debug my code Poke tongue | ;-P , if you are able to fix it, even post your message. Me and others would be definitely grateful to you. Big Grin | :-D
 
---------
Tittle
AnswerRe: JavaScript Errormembercliftmaples21 Dec '06 - 3:08 
This works in IIS6 with .Net 2.0 with VS2005
 
Just change the following lines in the ClientSide Javascript.
 
function MinMaxTableCurvePanel(cntrlId)
{

var closed_TableCurvePanel = document.getElementById(cntrlId).style.display;

if ( closed_TableCurvePanel.toLowerCase() == 'none' )
{

document.getElementById(cntrlId).style.display = '';
//document.getElementById(cntrlId+'_hdnMinimizeState').value=false;
document.getElementById(cntrlId+'_imgPlusMinus').src = 'images/minus.gif';
}
else
{
document.getElementById(cntrlId).style.display = 'none';
//document.getElementById(cntrlId+'_hdnMinimizeState').value = true;
document.getElementById(cntrlId+'_imgPlusMinus').src = 'images/plus.gif';
}
}
This bypasses the hidden field altogether, you don't need it. Use the style.display of the div itself to determine visibility.
 
Excellent Panel Control!!!

 
Clift B. Maples
Generalmaximise/minimise featuremembergooseman11222 May '06 - 19:05 
Hi, have been looking at your panel curve container over the last week.
 
with the maximise/minimise feature on the heading i was trying to get the minimise image to stay in the location when i click, to maximise the panel. To give contrast to what i mean, in your webform1.aspx for download
 
its acting like panel curve - custom tab color, when i expand the panel
but i want it to act like panel curve - without print icon, so it stays in the same spot,
 
what is it that causes it to stay in the same spot?
 
also would like to have the minimise/maximise to the left of the panel, where abouts to i go2 in your code to modify this feature
GeneralRe: maximise/minimise featurememberTittle Joseph22 May '06 - 22:37 
1. I remove space which is occupied by nugget when someone clicks on minimize button and due to which mouse position gets change, use ".style.visibility='visible'" and ".style.visibility='hidden'" instead of ".style.display=''" and ".style.display='none'" respectively, and this will hide the control but do not remove the space and this way mouse pointer position will remain same.OMG | :OMG:
2. There are exposed attributes, you can use them to decide whether to show a specific icon or not. Wink | ;)
3. There is a known bug where minimize icon shifts to left sometime (should be on extreme right), and i really dont know its resolution, you'll to study code a little to understand where i'm making mistake. D'Oh! | :doh:
4. Man code is yours, you can definitely take icons on left and text on right, change code the way you want Smile | :) , but i'll be happy knowing if this site gets hit because you have this page url on your code Poke tongue | ;-P .
 
---------
Tittle
GeneralRe: maximise/minimise featurememberAndy Moon7 Jul '06 - 16:58 
I believe I fixed the problem by assigning a width to the centercell of the tab.
 
int offset = 20;
if (hasPrint)
offset = offset + 20;
if (hasMinimize)
offset = offset + 20;
 
int centerwidth = (int) this.Width.Value - offset;
centerCell.Style.Add("width",centerwidth.ToString()+"px");
GeneralRe: maximise/minimise feature [modified]memberRonyMan17 Oct '07 - 21:36 
Andy Moon wrote:
I believe I fixed the problem by assigning a width to the centercell of the tab.
 
int offset = 20;
if (hasPrint)
offset = offset + 20;
if (hasMinimize)
offset = offset + 20;
 
int centerwidth = (int) this.Width.Value - offset;
centerCell.Style.Add("width",centerwidth.ToString()+"px");

 
I've tried this but I does not work.
 
It is a great control, but if this is not going the work, I can't use it.
The problem occurs when you put other html controls (table) inside. If you put only text in it (like just where you put 'content here') it works perfect.
 

 

-- modified at 4:49 Thursday 18th October, 2007
What I also tried:
If you put it in a usercontrol a then add tables, textboxes, labels inside the panelCurveContainer, the collapse and expand feature works fine. The plus and minus images stay in the correct region.
 


GeneralRe: maximise/minimise featurememberGrandson24 Sep '09 - 4:32 
I have found the solution for this problem.
 
Look for the part of code starting with the following comment:
// Insert the Panel's markup in the table cell {Container}
 
Comment some code above it
 
/*int colspan = 3;
if ( hasPrint )
colspan++;
if ( hasMinimize )
colspan++;*/
 

Аnd change code below it.
 

Table t2 = new Table();
t2.CellPadding = 0;
t2.CellSpacing = 0;
t2.Width = Unit.Percentage(100); //Width;
t2.HorizontalAlign = HorizontalAlign.Center;
t2.Style.Add("margin", "0 0 0 0px");
 
TableRow rowBody1 = new TableRow();
if ( bodyBackColor != Color.Transparent )
rowBody1.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"
 
rowBody1.Cells.Add(cellBody);
t2.Rows.Add(rowBody1);
 
// Output
t.RenderControl(output);
t2.RenderControl(output);
GeneralObject Reference not set to an instance of an object.membervyastapan20 May '06 - 4:22 
Hi, I am using the solution provided by you but when I am opening WebForm1.aspx of PanelCurveContainer project in design mode, it is not creating the PanelCurveControl saying "Object Reference not set to an instance of an object." Please needed a help, Very URGENT!!!!
 
Thanks in Advance,
Tapan Vyas D'Oh! | :doh:
GeneralRe: Object Reference not set to an instance of an object.memberTittle Joseph21 May '06 - 19:43 
Tapas,
 
If you had gone through entire question-answer section of this page you must have got ur answer Laugh | :laugh: . Actually it is missing Design time code implementation, lots of people have requested for this, and i never got time.. but I promise i'll take out time and write a design mode class for this. but trust me it will work even if it is showing error in IDE. So use this in page and open in IE and see how it works.
 
---------
Tittle
GeneralRe: Object Reference not set to an instance of an object. [modified]memberangelocba17 Jul '06 - 2:44 
Great Control Joseph!
this is what I was looking for. I have to study this a lot... Wink | ;)
 
To avoid that error in design mode I just commented out the line "imgPath"
 
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/";
}
 
and to get still working the images I appended that line in the Onload event
 
protected override void OnLoad(EventArgs e)
{
imgPath = HttpContext.Current.Request.ApplicationPath + skinName + "/Images/";
base.OnLoad(e);
..............
 
I'm pretty sure that there is a real and better solution, but just for now that works Big Grin | :-D ...

 
Angelo (from Córdoba, Argentina)
 
-- modified at 8:52 Monday 17th July, 2006
GeneralRe: Object Reference not set to an instance of an object.memberTittle Joseph26 Jul '06 - 3:57 
Angelo,
 
I appreciate your words, surely i'll try to make use of comments you added whenever I get time. That surely helps me.
 
Have a nice time. Smile | :)
Tittle
 
---------
Tittle

Generaljavascript error from asp:content tagmembergooseman11211 May '06 - 5:47 
thanks Tittle for your quick response, sorry didnt post new thread, just joined up and was keen to get this control implemented.
 
control comes up ok within my app but when i hit the minimise button it throws
 
Microsoft JScript runtime error: Object required and it points at this line of code
---->var closed_TableCurvePanel = document.getElementById(cntrlId+'_hdnMinimizeState').value;
 
which is within function MinMaxTableCurvePanel(cntrlId)
 
do you know if your control has any complications with the <asp:content> tag, as your control is currently sitting inside this tag on my page.
It works fine on pages without this web control around it.
 
also was wondering once you include the assembly can you promatically set the tittle web control and attributes
like a normal web control.
 
cheers
geoff.
 
-- modified at 0:25 Friday 12th May, 2006
GeneralRe: javascript error from asp:content tagmemberTittle Joseph21 May '06 - 19:53 
I checked this control inside DATAGRID, inside any other USER CONTROL, and it worked perfectly fine everywhere. Can you zip and email ur code to me, if i get time i can look into that.
 
Thanks
 
---------
Tittle
GeneralJavaScript Error in .NET TagmemberEdy G14 Apr '06 - 11:09 
I get a JavaScript error whenever I put the panel in a content area of my masterpage. Obviously I am using VS 2005 with Masterpages ... do you know what I can do about it? Have you ever tried it in a content area?
 
Any help ASAP would really help ... I would love to use this code!
 
Thanks to anyone who can help!!
 
Ed
 
-- modified at 17:09 Friday 14th April, 2006
GeneralRe: JavaScript Error in .NET TagmemberTittle Joseph19 Apr '06 - 4:38 
I COULD NEVER CHECK THIS IN VS 2005 AND IM NOT SURE EITHER IF IT WILL WORK, WHAT I BELIEVE IS IS THAT THERE MIGHT BE MUCH BETTER APPROACH IN VS.NET 2005 Big Grin | :-D
 
---------
Tittle
QuestionTab title shift on minimizememberFSZRM2 Mar '06 - 13:49 
In the demo project,consider the first PanelCurve control which has 2 textboxes. If we minimize the panel, the Title and the image are shifted
right and when we maximize the control they are shifted back.
why is this so ?
 
Thanks,
AnswerRe: Tab title shift on minimizememberTittle Joseph22 Mar '06 - 2:54 
There is slight space problem, and i'm not sure why it comes, but it only comes in a typical scenario not everytime, you may need to re-study html generated to fix this problem.
 
I'm busy with other things therefore cant fix it now.
 
---------
Tittle
GeneralJavascript ErrormemberGregKuper26 Jan '06 - 4:56 
I can not get the minimize to work. I am getting a javascript error "object required" Any ideas. Thanks for the work you have done it looks great!
 
Greg Kuper
GeneralRe: Javascript ErrormemberFSZRM2 Mar '06 - 11:37 
try setting the ID of the control....
GeneralRe: Javascript ErrormemberTittle Joseph2 Mar '06 - 17:51 
I've tested the application at my end and it works fine. I have IE 6.0.
 
To debug the error. either insert "debugger;" in the function you are getting error, or let debugger open when error occurs. "Tools/Options/Advanced "
Uncheck "disable script debugging..", check "display a notification error".
 
---------
Tittle
QuestionBrowser Compatability?memberjonwarren30 Dec '05 - 11:36 
What kind of browser compatability does this control have? Is it IE specific, or will it render properly in Firefox/Mozilla/Netscape?
AnswerRe: Browser Compatability?memberTittle Joseph1 Jan '06 - 18:44 
I just tested it with IE. It might be working with other browsers or it requires little modification to work with them. Please do it urself.
 
Smile | :)
 
---------
Tittle
GeneralServer Error in '/PanelCurveContainer' Application.memberjonwarren30 Dec '05 - 10:51 
When I try to View In Browser in VS 2005 standard edition, I get the following compilation error: What does this mean?
 
Server Error in '/PanelCurveContainer' Application.
--------------------------------------------------------------------------------
 
Configuration Error
Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.
 
Parser Error Message: It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.
 
Source Error:
 

Line 44: by Microsoft that offers a single logon and core profile services for member sites.
Line 45: -->
Line 46:
Line 47:
Line 48: <!-- AUTHORIZATION

 
Source File: C:\- Visual Studio 2005\Curved Collapsible Panel Control\PanelCurveContainer\panelcurvecontainer\web.config Line: 46
 

 
Show Additional Configuration Errors:
 

It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS. (C:\- Visual Studio 2005\Curved Collapsible Panel Control\PanelCurveContainer\panelcurvecontainer\web.config line 83)


 

--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.42
GeneralRe: Server Error in '/PanelCurveContainer' Application.memberTittle Joseph2 Mar '06 - 17:46 
I'm not able to reproduce error at my end. I have vs .net 2003 and it works fine there.
 
But I can suggest you how to resolve it, ie. open IIS "inetmgr.exe at RUN", right click on virtual directory u created, select properties. There is something called "ApplicationSettings", and there is a button called "Create/Remove" application. Click on "Create" which becomes "Remove" once clicked, if application hasnt been created. You must be able to resolve error now.
 
---------
Tittle
Generalvalidation summary controlmembermankeshk22 Nov '05 - 23:44 
I want to display images in validation summary control instead of 3 default display modes : these are 1. bulletted list 2. list 3. Paragraph
GeneralRe: validation summary controlmemberTittle Joseph23 Nov '05 - 2:18 
Should this question be really asked here? Anyway I give you answer.
 
Check the view source of html page, it must have generated some thing like below. e.g.
<table id="valSum" cellpadding="0" cellspacing="0" border="0" width="100%"><tr><td><font face="verdana" color="Red" size="3">You must enter a value in the following fields:<ul><li>Card Type. </li><li>Card Number. </li><li>Expiration Date. </li></ul>
</font></td></tr></table>
 
now create a style tag in ur page, and provide li image path.
 
e.g.
<style>
#valSum UL
{
   list-style-image: url(blueball.gif);
   list-style-type: circle
}
</style>
 
and this will show images instead of actual bullets.
 
I must have missed here some syntaxes, just typed them down from my old memories, so fix it when you face problem.
 
---------
Tittle
GeneralRe: validation summary controlmemberTittle Joseph26 Jul '06 - 3:59 
Mankesh,
 
D'Oh! | :doh: Your question do not at all belong to this forum. You should post it somewhere else.
 
Thanks
 
---------
Tittle

Questionhow to use with vs.net design modememberPeterCodeCode15 Nov '05 - 7:57 
Joseph, thanks for your control, it is extremely helpful to me.
 
I downloaded your demo project and although it runs great in the web browser, in Visual Studio design mode, all I get is "Error Creating Control - Panelcurvecontrol1 (i)". When I hover over the (i) it says "Object reference not set to an instance of an object".
 
The web form designer generated code #region doesn't show any variables for the PanelCurveControls for WebForm1.aspx.cs.
 
The same happens when I try to incorporate the control into my own project. The control is compiled and, like I said, it actually works in the web browser -- it is just VS.NET Design Mode that is messed up.
 
What am I doing wrong?
AnswerRe: how to use with vs.net design modememberTittle Joseph15 Nov '05 - 19:52 
I havent given it design support. Providing Design support to a custom control is tedious job in .Net. I was in hurry to release it without design support. Also I use images at corner to form the curve and I dont know image url while I'm in design mode, so it wont be exactly in design mode as it is going to appear on screen. So I dropped it.
 
Smile | :)
 
---------
Tittle
GeneralRe: how to use with vs.net design modememberPeterCodeCode16 Nov '05 - 9:57 
Ah, I see. That gave me a hint, though -- if you check to see if HttpContext.Current==null before setting imgPath (and just set it to "" if it's not blank), the control will construct in the designer and at least the controls inside it will still show up, even though the panel itself doesn't render correctly. Thanks.
QuestionRe: how to use with vs.net design modememberTittle Joseph16 Nov '05 - 18:17 
Sounds interesting, I'm still confused while in design mode how can be Context.Current could be ever not null? Do you have sample code related with this, I can definitely give design support then.
Smile | :)
 
---------
Tittle
AnswerRe: how to use with vs.net design modemembermickyg226 Dec '05 - 15:09 
Search for imgPath and replace with the following for VS support.
 
if (HttpContext.Current == null)
{
imgPath = "";
}
else
{
imgPath = HttpContext.Current.Request.ApplicationPath + skinName + "/Images/";
}
 
Mike
AnswerRe: how to use with vs.net design modemembermangeles16 Jan '06 - 14:41 
I'm not sure if I'm doing correctly but I can't view the panel in Design View. In the constructor I replace imgPath for the piece of code that is posted but Im' still getting Error Creating Control
 
Confused | :confused: Confused | :confused: . Any help =(
 
-- modified at 20:41 Monday 16th January, 2006
GeneralRe: how to use with vs.net design modememberTittle Joseph16 Jan '06 - 18:50 
hey,
 
I didnt get time to provide support for design mode. It wont work in design mode right now. Frown | :(
 

 
---------
Tittle
AnswerRe: how to use with vs.net design modemembergooseman11210 May '06 - 15:19 
Hi Tittle, your control looks really good and is exactly what i need.
only problem is not sure how to deploy it.
 
what is the procedure to bring this control into my app.
 
im using vs2005 and am not really sure what the process is.
Do i compile it into a .dll and include it in my project?
 
any advice would be great
 
-- modified at 6:39 Thursday 11th May, 2006
GeneralRe: how to use with vs.net design modememberTittle Joseph10 May '06 - 22:46 
You should have created a new thread:
 
Anyway first of all for your information i could test it with .net 2003 and not sure if it breaks in 2005, but still I think it should run.
 
Download the complete project and it has readme.txt, follow it and you would be able to use the control in any file once you understand that.
 
DLL will be generated by my control, i'm giv9ng you complete code (.cs) you can use it anywhere.

 
---------
Tittle

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 15 Nov 2005
Article Copyright 2005 by Tittle Joseph
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid