ASP.NET Tutorial/Custom Controls/WebControl

Материал из .Net Framework эксперт
Перейти к: навигация, поиск

A control that inherits from the WebControl class.

using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class FullyRenderedWebControl : WebControl
    {
        private string _Text;
        public string Text
        {
            get { return _Text; }
            set { _Text = value; }
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write(_Text);
        }
    }
}

File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Fully Rendered WebControl</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:FullyRenderedWebControl
        ID="FullyrenderedWebControl1"
        Text="Hello World"
        BackColor="Yellow"
        BorderStyle="Dashed"
        Font-Size="32px"
        Runat="Server" />
    </div>
    </form>
</body>
</html>


Applying Design-Time Attributes to a Control

File: ProductView.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ruponentModel;
namespace myControls
{
    [DefaultProperty("Title")]
    public class ProductView : WebControl
    {
        private string _title = "Product Title";
        private string _description = "Product Description";
        [Category("Product")]
        [Description("Product Title")]
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }
        [Category("Product")]
        [Description("Product Description")]
        public string Description
        {
            get { return _description; }
            set { _description = value; }
        }

        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.H1);
            writer.Write(_title);
            writer.RenderEndTag();
            writer.Write(_description);
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
    }
}
File: ShowProductView.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show ProductView</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ProductView
        id="ProductView1"
        Runat="server" />
    </div>
    </form>
</body>
</html>


contains the custom pager control.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class Pager : WebControl, IPostBackEventHandler
    {
        string _controlToPage;
        public string ControlToPage
        {
            get { return _controlToPage; }
            set { _controlToPage = value; }
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            GridView grid = GetControlToPage();
            for (int i = 0; i < grid.PageCount; i++)
            {
                string eRef = Page.ClientScript.GetPostBackClientHyperlink(this, i.ToString());
                writer.Write("[");
                if (i == grid.PageIndex)
                   writer.AddStyleAttribute(HtmlTextWriterStyle.FontWeight, "bold");
                writer.AddAttribute(HtmlTextWriterAttribute.Href, eRef);
                writer.RenderBeginTag(HtmlTextWriterTag.A);
                writer.Write("{0}", i + 1);
                writer.RenderEndTag();
                writer.Write("] ");
            }
        }
        private GridView GetControlToPage()
        {
            if (String.IsNullOrEmpty(_controlToPage))
                throw new Exception("Must set ControlToPage property");
            return (GridView)Page.FindControl(_controlToPage);
        }
        public void RaisePostBackEvent(string eventArgument)
        {
            GridView grid = GetControlToPage();
            grid.PageIndex = Int32.Parse(eventArgument);
        }
    }
}
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show CustomPager</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:GridView
        id="GridView1"
        DataSourceID="srcProducts"
        AllowPaging="true"
        PageSize="3"
        PagerSettings-Visible="false"
        Runat="server" />
    <custom:Pager
        id="Pager1"
        ControlToPage="GridView1"
        Runat="server" />
    <asp:SqlDataSource
        id="srcProducts"
        ConnectionString="Data Source=.\SQLExpress;Integrated Security=True;
            AttachDbFileName=|DataDirectory|MyDatabase.mdf;User Instance=True"
        SelectCommand="SELECT Id,Title,Director FROM Products"
        Runat="server" />
    </div>
    </form>
</body>
</html>


Creating a Container ControlDesigner

Add a reference to the System.Design.dll assembly to your application.
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;
using System.ruponentModel;
using System.Drawing;
namespace myControls
{
    [Designer(typeof(GradientPanelDesigner))]
    [ParseChildren(false)]
    public class GradientPanel : WebControl
    {
        private GradientDirection _direction = GradientDirection.Horizontal;
        private Color _startColor = Color.DarkBlue;
        private Color _endColor = Color.White;
        public GradientDirection Direction
        {
            get { return _direction; }
            set { _direction = value; }
        }
        public Color StartColor
        {
            get { return _startColor; }
            set { _startColor = value; }
        }
        public Color EndColor
        {
            get { return _endColor; }
            set { _endColor = value; }
        }
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            writer.AddStyleAttribute(HtmlTextWriterStyle.Filter, this. GetFilterString());
            base.AddAttributesToRender(writer);
        }        public string GetFilterString()
        {
            return String.Format("progid:DXImageTransform.Microsoft.Gradient (gradientType={0},startColorStr={1},endColorStr={2})", _direction.ToString("d"), ColorTranslator.ToHtml(_startColor), ColorTranslator.ToHtml(_endColor));
        }
        public GradientPanel()
        {
            this.Width = Unit.Parse("500px");
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
    }
    public enum GradientDirection
    {
        Vertical = 0,
        Horizontal = 1
    }
    public class GradientPanelDesigner : ContainerControlDesigner
    {
        protected override void AddDesignTimeCssAttributes(System.Collections. IDictionary styleAttributes)
        {
            GradientPanel gPanel = (GradientPanel)this.ruponent;
            styleAttributes.Add("filter", gPanel.GetFilterString());
            base.AddDesignTimeCssAttributes(styleAttributes);
        }
    }
}
            

Open the page in Design view in either Visual Web Developer or Visual Studio .NET.
File: ShowGradientPanel.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show GradientPanel</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:GradientPanel
        id="GradientPanel1"
        Runat="server">
        <asp:Calendar
            ID="Calendar1"
            runat="server" />
    </custom:GradientPanel>
    </div>
    </form>
</body>
</html>


Displaying a table of HTML colors.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
namespace myControls
{
    public class ColorTable : WebControl
    {
        protected override void RenderContents(HtmlTextWriter writer)
        {
            KnownColor[] colors = (KnownColor[])Enum.GetValues(typeof(KnownColor));
            writer.AddAttribute(HtmlTextWriterAttribute.Border, "1");
            writer.RenderBeginTag(HtmlTextWriterTag.Table);
            foreach (KnownColor colorName in colors)
            {
                writer.RenderBeginTag(HtmlTextWriterTag.Tr);
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.Write(colorName);
                writer.RenderEndTag();
                writer.AddAttribute(HtmlTextWriterAttribute.Width, "50px");
                writer.AddAttribute(HtmlTextWriterAttribute.Bgcolor, colorName.ToString());
                writer.RenderBeginTag(HtmlTextWriterTag.Td);
                writer.Write("&nbsp;");
                writer.RenderEndTag();
                writer.RenderEndTag();
            }
            writer.RenderEndTag();
        }
    }
}


File: DropShadow.cs

using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class DropShadow : WebControl
    {
        private string _Text;
        public string Text
        {
            get { return _Text; }
            set { _Text = value; }
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.AddStyleAttribute(HtmlTextWriterStyle.Filter, "dropShadow(color=#AAAAAA,offX=3,offY=3);width:500px");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.Write(_Text);
            writer.RenderEndTag();
        }
    }
}


Handling Postback Events

File: CustomLinkButton.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class CustomLinkButton : WebControl, IPostBackEventHandler
    {
        public event EventHandler Click;
        private string _Text;
        public string Text
        {
            get { return _Text; }
            set { _Text = value; }
        }
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            string eRef = Page.ClientScript.GetPostBackClientHyperlink(this, String.Empty);
            writer.AddAttribute(HtmlTextWriterAttribute.Href, eRef);
            base.AddAttributesToRender(writer);
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.A;
            }
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write(_Text);
        }

        public void RaisePostBackEvent(string eventArgument)
        {
            if (Click != null)
                Click(this, EventArgs.Empty);
        }
    }
}
            
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    protected void CustomLinkButton1_Click(object sender, EventArgs e)
    {
        lblResults.Text = txtUserName.Text;
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show CustomLinkButton</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Label
        id="lblUserName"
        Text="User Name:"
        AssociatedControlID="txtUserName"
        Runat="server" />
    <asp:TextBox
        id="txtUserName"
        Runat="server" />
    <br /><br />
    <custom:CustomLinkButton
        id="CustomLinkButton1"
        Text="Submit"
        OnClick="CustomLinkButton1_Click"
        runat="server" />
    <hr />
    <asp:Label
        id="lblResults"
        EnableViewState="false"
        Runat="server" />
    </div>
    </form>
</body>
</html>


Processing Postback Data and Events

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class CustomTextBox : WebControl, IPostBackDataHandler
    {
        public event EventHandler TextChanged;
        public string Text        {
            get
            {
                if (ViewState["Text"] == null)
                    return String.Empty;
                else
                    return (string)ViewState["Text"];
            }
            set { ViewState["Text"] = value; }
        }
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
            writer.AddAttribute(HtmlTextWriterAttribute.Value, Text);
            writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
            base.AddAttributesToRender(writer);
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Input;
            }
        }
        public bool LoadPostData(string postDataKey, System.Collections. Specialized.NameValueCollection postCollection)
        {
            if (postCollection[postDataKey] != Text)
            {
                Text = postCollection[postDataKey];
                return true;
            }
            return false;
        }
        public void RaisePostDataChangedEvent()
        {
            if (TextChanged != null)
                TextChanged(this, EventArgs.Empty);
        }
    }
}
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    protected void CustomTextBox1_TextChanged(object sender, EventArgs e)
    {
        lblResults.Text = CustomTextBox1.Text;
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show CustomTextBox</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:CustomTextBox
        id="CustomTextBox1"
        OnTextChanged="CustomTextBox1_TextChanged"
        Runat="server" />
    <asp:Button id="btnSubmit"
        Text="Submit"
        Runat="server" />
    <hr />
    <asp:Label
        id="lblResults"
        Runat="server" />
    </div>
    </form>
</body>
</html>


Specifying the Containing WebControl Tag

File: Glow.cs
using System.Web.UI;
using System.Web.UI.WebControls;namespace myControls
{
    public class Glow : WebControl
    {
        private string _Text;
        public string Text
        {
            get { return _Text; }
            set { _Text = value; }
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            writer.AddStyleAttribute(HtmlTextWriterStyle.Filter, "glow(Color=#ffd700,Strength=10)");
            base.AddAttributesToRender(writer);
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write(_Text);
        }
        public Glow()
        {
            this.Width = Unit.Parse("500px");
        }
    }
}


Supporting Control State

File: ControlStateControl.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class ControlStateControl : WebControl
    {
        private string _controlStateText;
        public string ViewStateText
        {
            get
            {
                if (ViewState["ViewStateText"] == null)
                    return String.Empty;
                else
                    return (string)ViewState["ViewStateText"];
            }
            set { ViewState["ViewStateText"] = value; }
        }
        public string ControlStateText
        {
            get { return _controlStateText; }
            set { _controlStateText = value; }
        }
        protected override void OnInit(EventArgs e)
        {
            Page.RegisterRequiresControlState(this);
            base.OnInit(e);
        }
        protected override object SaveControlState()
        {
            return _controlStateText;
        }
        protected override void LoadControlState(object savedState)
        {
            _controlStateText = (string)savedState;
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write("ViewStateText: " + ViewStateText);
            writer.WriteBreak();
            writer.Write("ControlStateText: " + ControlStateText);
            writer.WriteBreak();
        }
    }
}
            
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    void Page_Load()
    {
        if (!Page.IsPostBack)
        {
            ControlStateControl1.ViewStateText = "Hello World!";
            ControlStateControl1.ControlStateText = "Hello World!";
        }
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Control State</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ControlStateControl
        id="ControlStateControl1"
        EnableViewState="false"
        Runat="server" />
    <asp:Button
        id="btnSubmit"
        Text="Submit"
        Runat="server" />
    </div>
    </form>
</body>
</html>


Using a ControlBuilder

File: ServerTabs.cs
using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    [ControlBuilder(typeof(ServerTabsBuilder))]
    [ParseChildren(false)]
    public class ServerTabs : WebControl, IPostBackEventHandler
    {
        public int SelectedTabIndex
        {
            get
            {
                if (ViewState["SelectedTabIndex"] == null)
                    return 0;
                else
                    return (int)ViewState["SelectedTabIndex"];
            }            set
            {
                ViewState["SelectedTabIndex"] = value;
            }
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            for (int i = 0; i < this.Controls.Count; i++)
            {
                ServerTab tab = (ServerTab)this.Controls[i];
                string eRef = Page.ClientScript.GetPostBackClientHyperlink(this,  i.ToString());
                if (SelectedTabIndex == i)
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "tab  selectedTab");
                else
                    writer.AddAttribute(HtmlTextWriterAttribute.Class, "tab");
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.AddAttribute(HtmlTextWriterAttribute.Href, eRef);
                writer.RenderBeginTag(HtmlTextWriterTag.A);
                writer.Write(tab.Text);
                writer.RenderEndTag();
                writer.RenderEndTag();
            }
            writer.Write("<br style="clear:both" />");
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "tabContents");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            this.Controls[SelectedTabIndex].RenderControl(writer);
            writer.RenderEndTag(); 
        }
        protected override void AddParsedSubObject(object obj)
        {
            if (obj is ServerTab)
                base.AddParsedSubObject(obj);
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
        public void RaisePostBackEvent(string eventArgument)
        {
            SelectedTabIndex = Int32.Parse(eventArgument);
        }
    }
    public class ServerTabsBuilder : ControlBuilder
    {
        public override Type GetChildControlType(string tagName, IDictionary attribs)
        {
            if (String.rupare(tagName, "tab", true) == 0)
                return typeof(ServerTab);
            else
                return null;
        }
    }
    public class ServerTab : Control
    {
        private string _Text;
        public string Text
        {
            get { return _Text; }
            set { _Text = value; }
        }
    }
}
            
File: ShowServerTabs.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .tab
        {
            float:left;
            position:relative;
            top:1px;
            background-color:#eeeeee;
            border:solid 1px black;
            padding:0px 15px;
            margin-left:5px;
        }
        .tab a
        {
            text-decoration:none;
        }
        .selectedTab
        {
            background-color:white;
            border-bottom:solid 1px white;
        }
        .tabContents
        {
            border:solid 1px black;
            background-color:white;
            padding:10px;
            height:200px;
        }
    </style>
    <title>Show ServerTabs</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ServerTabs
        ID="ServerTabs1"
        Runat="Server">
        <tab Text="First Tab">
          Contents of the first tab
        </tab>
        <tab Text="Second Tab">
          Contents of the second tab
        </tab>
        <tab Text="Third Tab">
          Contents of the third tab
        </tab>
    </custom:ServerTabs>
    </div>
    </form>
</body>
</html>


Using Postback Options

File: AdvancedCheckBox.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class AdvancedCheckBox : WebControl
    {
        private string _Text;
        private string _PostBackUrl;
        public string Text
        {
            get { return _Text; }
            set { _Text = value; }
        }
        public string PostBackUrl
        {
            get { return _PostBackUrl; }
            set { _PostBackUrl = value; }
        }
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            PostBackOptions options = new PostBackOptions(this);
            options.ActionUrl = _PostBackUrl;
            string eRef = Page.ClientScript.GetPostBackEventReference(options);
            writer.AddAttribute(HtmlTextWriterAttribute.Onclick, eRef);
            writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
            writer.AddAttribute(HtmlTextWriterAttribute.Type, "checkbox");

            base.AddAttributesToRender(writer);
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            if (!String.IsNullOrEmpty(_Text))
            {
                writer.AddAttribute(HtmlTextWriterAttribute.For, this.ClientID);
                writer.RenderBeginTag(HtmlTextWriterTag.Label);
                writer.Write(_Text);
                writer.RenderEndTag();
            }
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Input;
            }
        }
    }
}
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    public string ProductName
    {
        get { return txtProductName.Text; }
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show AdvancedCheckBox</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Label
        id="lblProductName"
        Text="Product Name:"
        AssociatedControlID="txtProductName"
        Runat="server" />
    <asp:TextBox
        id="txtProductName"
        Runat="server" />
    <br /><br />
    <custom:AdvancedCheckBox
        id="AdvancedCheckBox1"
        Text="Advanced Options"
        PostBackUrl="AdvancedOptions.aspx"
        Runat="server" />
    </div>
    </form>
</body>
</html>


View State and Control State

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class ViewStateControl : WebControl
    {
        private string _text;
        public string Text
        {
            get { return _text; }
            set { _text = value; }
        }
        public string ViewStateText
        {
            get
            {
                if (ViewState["ViewStateText"] == null)
                    return String.Empty;
                else
                    return (string)ViewState["ViewStateText"];
            }
            set { ViewState["ViewStateText"] = value; }
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.Write("Text: " + Text);
            writer.WriteBreak();
            writer.Write("ViewStateText: " + ViewStateText);
            writer.WriteBreak();
        }
    }
}
            
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    void Page_Load()
    {
        if (!Page.IsPostBack)
        {
            ViewStateControl1.Text = "Hello World!";
            ViewStateControl1.ViewStateText = "Hello World!";
        }
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Show View State</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ViewStateControl
        id="ViewStateControl1"
        Runat="server" />
    <asp:Button
        id="btnSubmit"
        Text="Submit"
        Runat="server" />
    </div>
    </form>
</body>
</html>


Working with Control Property Collections

File: ContentRotator.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    [ParseChildren(false)]
    public class ContentRotator : WebControl
    {
        protected override void AddParsedSubObject(object obj)
        {
            if (obj is Content)
                base.AddParsedSubObject(obj);
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            Random rnd = new Random();
            int index = rnd.Next(this.Controls.Count);
            this.Controls[index].RenderControl(writer);
        }
    }
    public class Content : Control
    {
    }
}
            
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show ContentRotator</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ContentRotator
        id="ContentRotator1"
        Runat="server">
        <custom:Content
            id="Content1"
            Runat="server">
            First Content Item
        </custom:Content>
        <custom:Content
            id="Content2"
            Runat="server">
            Second Content Item
            <asp:Calendar
                id="Calendar1"
                Runat="server" />
        </custom:Content>
        <custom:Content
            id="Content3"
            Runat="server">
            Third Content Item
        </custom:Content>
    </custom:ContentRotator>
    </div>
    </form>
</body>
</html>


You can add your own Smart Tasks to a custom control by inheriting a new class from the base DesignerActionList class.

using System;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.Design;using System.ruponentModel;
using System.ruponentModel.Design;
namespace myControls
{
    [Designer(typeof(SmartImageDesigner))]
    public class SmartImage : WebControl
    {
        string _imageUrl;
        string _alternateText;
        int _rotation = 0;
        bool _mirror = false;
        public string ImageUrl
        {
            get { return _imageUrl; }
            set { _imageUrl = value; }
        }
        public string AlternateText
        {
            get { return _alternateText; }
            set { _alternateText = value; }
        }
        public int Rotation
        {
            get { return _rotation; }
            set { _rotation = value; }
        }
        public bool Mirror
        {
            get { return _mirror; }
            set { _mirror = value; }
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Img;
            }
        }        private string GetFilterString()
        {
            string _mirrorValue = "0";
            if (_mirror)
                _mirrorValue = "1";
            return String.Format("progid:DXImageTransform.Microsoft. BasicImage(Rotation={0},Mirror={1})", _rotation, _mirrorValue);
        }
        protected override void AddAttributesToRender(HtmlTextWriter writer)
        {
            writer.AddStyleAttribute(HtmlTextWriterStyle.Filter, this. GetFilterString());
            writer.AddAttribute(HtmlTextWriterAttribute.Src, _imageUrl);
            writer.AddAttribute(HtmlTextWriterAttribute.Alt, _alternateText);

            base.AddAttributesToRender(writer);
        }
    }
    public class SmartImageDesigner : ControlDesigner
    {
        public override DesignerActionListCollection ActionLists
        {
            get
            {
                DesignerActionListCollection actionLists = new DesignerActionListCollection();
                actionLists.AddRange(base.ActionLists);
                actionLists.Add(new SmartImageActionList(this));
                return actionLists;
            }
        }
    }
    public class SmartImageActionList : DesignerActionList
    {
        private DesignerActionItemCollection items;
        private SmartImageDesigner _parent;
        public SmartImageActionList(SmartImageDesigner parent)
            : base(parent.ruponent)        {
            _parent = parent;
        }
        public void Rotate()
        {
            TransactedChangeCallback toCall = new TransactedChangeCallback(DoRotate);
            ControlDesigner.InvokeTransactedChange(this.ruponent, toCall, "Rotate", "Rotate image 90 degrees");
        }
        public void Mirror()
        {
            TransactedChangeCallback toCall = new TransactedChangeCallback(DoMirror);
            ControlDesigner.InvokeTransactedChange(this.ruponent, toCall, "Mirror", "Mirror Image");
        }
        public override DesignerActionItemCollection GetSortedActionItems()
        {
            if (items == null)
            {
                items = new DesignerActionItemCollection();
                items.Add(new DesignerActionMethodItem(this, "Rotate", "Rotate Image", true));
                items.Add(new DesignerActionMethodItem(this, "Mirror", "Mirror Image", true));
            }
            return items;
        }
        public bool DoRotate(object arg)
        {
            SmartImage img = (SmartImage)this.ruponent;
            img.Rotation += 1;
            if (img.Rotation > 3)
                img.Rotation = 0;
            _parent.UpdateDesignTimeHtml();
            return true;
        }
        public bool DoMirror(object arg)
        {
            SmartImage img = (SmartImage)this.ruponent;
            img.Mirror = !img.Mirror;
            _parent.UpdateDesignTimeHtml();
            return true;
        }
    }
}


Your own data binding control

File: Article.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class Article : CompositeControl
    {
        private string _title;
        private string _author;
        private string _contents;
        private ITemplate _itemTemplate;
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }
        public string Author
        {
            get { return _author; }
            set { _author = value; }
        }
        public string Contents
        {
            get { return _contents; }
            set { _contents = value; }
        }
        [TemplateContainer(typeof(Article))]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set { _itemTemplate = value; }
        }
        protected override void CreateChildControls()
        {
            _itemTemplate.InstantiateIn(this);
        }
    }
}
            
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="myControls" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<script runat="server">
    void Page_Load()
    {
        Article1.Title = "your title";
        Article1.Author = "your name";
        Article1.Contents = "Blah, blah, blah, blah...";
        Article1.DataBind();
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Article</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:Article
        id="Article1"
        Runat="server">
        <ItemTemplate>
        <h1><%# Container.Title %></h1>
        <em>By <%# Container.Author %></em>
        <br /><br />
        <%# Container.Contents %>
        </ItemTemplate>
    </custom:Article>
    </div>
    </form>
</body>
</html>