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:
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";
else
hdn.ID = this.UniqueID + "_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)
[ToolboxData(
"<{0}:PanelCurveControl runat=
server Expandable='true' id='tblCrvPnl' Width='200px'>")]
public class PanelCurveControl : Panel, IPostBackDataHandler
{
private string skinName = "";
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/";
}
[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;}
}
[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;}
}
[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;}
}
[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;}
}
[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;}
}
[Browsable(true),
Category("Behavior"),
DefaultValue("BasicNuggetSkin"),
Description ("Skinname to be used in nugget.") ]
public string SkinName
{
get{ return skinName;}
set{ skinName = value;}
}
[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;}
}
[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;}
}
[Browsable(true),
Category("Appearance"),
DefaultValue("false"),
Description ("Render it minimized by default or not.") ]
public bool DefaultMinimize
{
get{ return Closed;}
set{ Closed = value;}
}
public Color BodyBackColor
{
get { return bodyBackColor; }
set { bodyBackColor = value; }
}
public string TabBackColor
{
get { return tabBackColor; }
set { tabBackColor = value; }
}
public string HeaderTextColor
{
get { return headerTextColor; }
set { headerTextColor = value; }
}
public virtual bool LoadPostData(string postDataKey,
NameValueCollection postCollection)
{
bool currentValueOfClosed = Closed;
bool postedValueOfClosed =
Convert.ToBoolean(postCollection[postDataKey+
"_hdnMinimizeState"]);
if (!currentValueOfClosed.Equals(postedValueOfClosed))
{
Closed = postedValueOfClosed;
return true;
}
return false;
}
public virtual void RaisePostDataChangedEvent()
{
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
bool uplevel = false;
HttpBrowserCapabilities caps = Page.Request.Browser;
if (caps.Browser.ToUpper().IndexOf("IE") > -1)
{
if (caps.MajorVersion >4)
uplevel = true;
}
if (!uplevel)
{
Expandable = false;
RenderInBox = true;
}
Page.RegisterRequiresPostBack(this);
}
protected override void Render(HtmlTextWriter output)
{
if (!Expandable)
{
if (!RenderInBox)
base.Render(output);
else
RenderContentsInBox(output);
return;
}
Style["margin"] = Margin.ToString();
Style["display"] = (Closed ?"none" :"");
Unit oldWidth = Width;
Width = Unit.Percentage(100);
TextBox hdn = new TextBox();
hdn.Attributes.Add("style","display:none");
if ( this.UniqueID.IndexOf(":") >=0 )
hdn.ID = this.ID + "_hdnMinimizeState";
else
hdn.ID = this.UniqueID + "_hdnMinimizeState";
hdn.Text = Closed.ToString();
this.Controls.Add(hdn);
StringWriter writer = new StringWriter();
HtmlTextWriter buffer = new HtmlTextWriter(writer);
base.Render(buffer);
string panelOutput = writer.ToString();
Width = oldWidth;
BuildControlTree(output, this.ClientID, panelOutput);
return;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
CreateClientScript();
}
private void BuildControlTree(HtmlTextWriter output,
string id, string panelOutput)
{
Table t = new Table();
t.ID = id + "_thePanel";
t.CellPadding = 0;
t.CellSpacing = 0;
t.Width = Unit.Percentage(100);
t.HorizontalAlign = HorizontalAlign.Center;
t.Style.Add("margin", "0 0 0 0px");
TableRow rowTop = new TableRow();
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);
TableCell centerCell = new TableCell();
centerCell.Style.Add("background-Color",tabBackColor);
centerCell.Wrap = false;
centerCell.Attributes.Add("onselectstart","return false");
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);
if ( hasPrint )
{
TableCell printCell = new TableCell();
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);
}
if ( hasMinimize )
{
TableCell minimizeCell = new TableCell();
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 = 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);
}
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);
t.Rows.Add(rowTop);
int colspan = 3;
if ( hasPrint )
colspan++;
if ( hasMinimize )
colspan++;
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");
cellBody.Style.Add("margin","0 0 0 0px");
rowBody.Cells.Add(cellBody);
t.Rows.Add(rowBody);
t.RenderControl(output);
}
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 );
}
private void RenderContentsInBox(HtmlTextWriter output)
{
this.Style.Add("BORDER","#cccccc 1px solid");
this.Style.Add("padding","0 0 0 0px");
this.Style.Add("margin","0 0 0 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
- 15th November, 2005: Created