ASP.NET Tutorial/Custom Controls/CompositeControl

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

Building Composite Controls

using System;
using System.Web.UI.WebControls;
namespace myControls
{
    public class RequiredTextBox : CompositeControl
    {
        private TextBox input;
        private RequiredFieldValidator validator;
        public string Text
        {
            get
            {
                EnsureChildControls();
                return input.Text;
            }
            set
            {
                EnsureChildControls();
                input.Text = value;
            }
        }
        protected override void CreateChildControls()
        {
            input = new TextBox();
            input.ID = "input";
            this.Controls.Add(input);
            validator = new RequiredFieldValidator();
            validator.ID = "valInput";
            validator.ControlToValidate = input.ID;
            validator.ErrorMessage = "(Required)";
            validator.Display = ValidatorDisplay.Dynamic;
            this.Controls.Add(validator);
        }
    }
}
File: Default.aspx

<%@ Page Language="C#" Trace="true" %>
<%@ 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 btnSubmit_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 RequiredTextBox</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <asp:Label
        ID="lblUserName"
        Text="User Name:"
        AssociatedControlID="txtUserName"
        Runat="server" />
    <custom:RequiredTextBox
        ID="txtUserName"
        Runat="Server" />
    <br />
    <asp:Button
        ID="btnSubmit"
        Text="Submit"
        Runat="server" OnClick="btnSubmit_Click" />
    <hr />
    <asp:Label
        id="lblResults"
        Runat="server" />
    </div>
    </form>
</body>
</html>


Building Hybrid Controls

File: Login.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class Login : CompositeControl
    {
        private TextBox txtUserName;
        private TextBox txtPassword;
        public string UserName
        {
            get
            {
                EnsureChildControls();
                return txtUserName.Text;
            }
            set
            {
                EnsureChildControls();
                txtUserName.Text = value;
            }
        }
        public string Password
        {
            get
            {
                EnsureChildControls();
                return txtPassword.Text;
            }
            set
            {
                EnsureChildControls();
                txtPassword.Text = value;
            }
        }
        protected override void CreateChildControls()
        {
            txtUserName = new TextBox();
            txtUserName.ID = "txtUserName";
            this.Controls.Add(txtUserName);
            txtPassword = new TextBox();
            txtPassword.ID = "txtPassword";
            txtPassword.TextMode = TextBoxMode.Password;
            this.Controls.Add(txtPassword);
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.AddAttribute(HtmlTextWriterAttribute.For, txtUserName.ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Label);
            writer.Write("User Name:");
            writer.RenderEndTag(); // Label
            writer.RenderEndTag(); // TD
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            txtUserName.RenderControl(writer);
            writer.RenderEndTag(); // TD
            writer.RenderEndTag();
            writer.RenderBeginTag(HtmlTextWriterTag.Tr);
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            writer.AddAttribute(HtmlTextWriterAttribute.For, txtPassword.ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Label);
            writer.Write("Password:");
            writer.RenderEndTag(); // Label
            writer.RenderEndTag(); // TD
            writer.RenderBeginTag(HtmlTextWriterTag.Td);
            txtPassword.RenderControl(writer);
            writer.RenderEndTag(); // TD
            writer.RenderEndTag(); // TR
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Table;
            }
        }
    }
}


Creating a Default Template

File: ArticleWithDefault.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class ArticleWithDefault : 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(ArticleWithDefault))]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set { _itemTemplate = value; }
        }
        protected override void CreateChildControls()
        {
            if (_itemTemplate == null)
                _itemTemplate = new ArticleDefaultTemplate();
            _itemTemplate.InstantiateIn(this);
        }
    }
    public class ArticleDefaultTemplate : ITemplate
    {
        public void InstantiateIn(Control container)
        {
            Label lblTitle = new Label();
            lblTitle.DataBinding += new EventHandler(lblTitle_DataBinding);
            Label lblAuthor = new Label();
            lblAuthor.DataBinding += new EventHandler(lblAuthor_DataBinding);
            Label lblContents = new Label();
            lblContents.DataBinding += new EventHandler(lblContents_DataBinding);
            container.Controls.Add(lblTitle);
            container.Controls.Add(new LiteralControl("<br />"));
            container.Controls.Add(lblAuthor);
            container.Controls.Add(new LiteralControl("<br />"));
            container.Controls.Add(lblContents);
        }
        void lblTitle_DataBinding(object sender, EventArgs e)
        {
            Label lblTitle = (Label)sender;
            ArticleWithDefault container = (ArticleWithDefault)lblTitle. NamingContainer;
            lblTitle.Text = container.Title;
        }
        void lblAuthor_DataBinding(object sender, EventArgs e)
        {
            Label lblAuthor = (Label)sender;
            ArticleWithDefault container = (ArticleWithDefault)lblAuthor. NamingContainer;
            lblAuthor.Text = container.Author;
        }
        void lblContents_DataBinding(object sender, EventArgs e)
        {
            Label lblContents = (Label)sender;
            ArticleWithDefault container = (ArticleWithDefault)lblContents. NamingContainer;
            lblContents.Text = container.Contents;
        }
    }
}
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()
    {
        ArticleWithDefault1.Title = "Creating Templated Databound Controls";
        ArticleWithDefault1.Author = "AAA";
        ArticleWithDefault1.Contents = "content";
        ArticleWithDefault1.DataBind();
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Article with Default Template</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ArticleWithDefault
        id="ArticleWithDefault1"
        Runat="server" />
    </div>
    </form>
</body>
</html>


Creating Templated Databound Controls

File: DivView.cs
using System;
using System.Collections;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace MyNamespace
{
    public class DivView : CompositeDataBoundControl
    {
        private ITemplate _itemTemplate;
        [TemplateContainer(typeof(DivViewItem))]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set { _itemTemplate = value; }
        }
        protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
        {
            int counter = 0;
            foreach (object dataItem in dataSource)
            {
                DivViewItem contentItem = new DivViewItem(dataItem, counter);
                _itemTemplate.InstantiateIn(contentItem);
                Controls.Add(contentItem);
                counter++;
            }
            DataBind(false);
            return counter;
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
    }

    public class DivViewItem : WebControl, IDataItemContainer
    {
        private object _dataItem;
        private int _index;
        public object DataItem
        {
            get { return _dataItem; }
        }
        public int DataItemIndex
        {
            get { return _index; }
        }
        public int DisplayIndex
        {
            get { return _index; }
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
        public DivViewItem(object dataItem, int index)
        {
            _dataItem = dataItem;
            _index = index;
        }
    }
}
File: Default.aspx
<%@ Page Language="C#" %>
<%@ Register TagPrefix="custom" Namespace="MyNamespace" %>
<!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">
        .products
        {
            width:500px;
        }
        .products div
        {
            border:solid 1px black;
            padding:10px;
            margin:10px;
        }
    </style>
    <title>Show DivView</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:DivView
        id="lstProducts"
        DataSourceID="srcProducts"
        CssClass="products"
        Runat="Server">
        <ItemTemplate>
        <h1><%# Eval("Title") %></h1>
        Director: <%# Eval("Director") %>
        </ItemTemplate>
    </custom:DivView>

    <asp:SqlDataSource
        id="srcProducts"
        ConnectionString="<%$ ConnectionStrings:Products %>"
        SelectCommand="SELECT Title, Director FROM Products"
        Runat="server" />
    <br />
    <asp:LinkButton
        id="lnkReload"
        Text="Reload"
        Runat="server" />
    </div>
    </form>
</body>
</html>


File: Product.cs

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class Product : CompositeControl
    {
        private ITemplate _itemTemplate;
        private ProductItem _item;
        public string Name
        {
            get
            {
                EnsureChildControls();
                return _item.Name;
            }
            set
            {
                EnsureChildControls();
                _item.Name = value;
            }
        }
        public Decimal Price
        {
            get
            {
                EnsureChildControls();
                return _item.Price;
            }
            set
            {
                EnsureChildControls();
                _item.Price = value;
            }
        }
        [TemplateContainer(typeof(ProductItem))]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public ITemplate ItemTemplate
        {
            get { return _itemTemplate; }
            set { _itemTemplate = value; }
        }
        protected override void CreateChildControls()
        {
            _item = new ProductItem();
            _itemTemplate.InstantiateIn(_item);
            Controls.Add(_item);
        }
    }
    public class ProductItem : WebControl, IDataItemContainer
    {
        private string _name;
        private decimal _price;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public decimal Price
        {
            get { return _price; }
            set { _price = value; }
        }
        public object DataItem
        {
            get
            {
                return this;
            }
        }
        public int DataItemIndex
        {
            get { return 0; }
        }
        public int DisplayIndex
        {
            get { return 0; }
        }
    }

}
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()
    {
        Product1.Name = "Laptop Computer";
        Product1.Price = 1254.12m;
        Product1.DataBind();
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show Product</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:Product
        id="Product1"
        Runat="Server">
        <ItemTemplate>
        Name: <%# Eval("Name") %>
        <br />
        Price: <%# Eval("Price", "{0:c}") %>
        </ItemTemplate>
    </custom:Product>
    </div>
    </form>
</body>
</html>


Image Rotator

File: ImageRotator.cs
using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ruponentModel;
namespace myControls
{
    [ParseChildren(true, "ImageItems")]
    public class ImageRotator : WebControl
    {
        private ArrayList _imageItems = new ArrayList();
        public ArrayList ImageItems
        {
            get
            {
                return _imageItems;
            }
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            if (_imageItems.Count > 0)
            {
                Random rnd = new Random();
                ImageItem img = (ImageItem)_imageItems[rnd.Next (_imageItems.Count)];
                writer.AddAttribute(HtmlTextWriterAttribute.Src, img.ImageUrl);
                writer.AddAttribute(HtmlTextWriterAttribute.Alt, img.AlternateText);
                writer.RenderBeginTag(HtmlTextWriterTag.Img);
                writer.RenderEndTag();
            }
        }
    }
    public class ImageItem
    {
        private string _imageUrl;
        private string _alternateText;
        public string ImageUrl
        {
            get { return _imageUrl; }
            set { _imageUrl = value; }
        }
        public string AlternateText
        {
            get { return _alternateText; }
            set { _alternateText = value; }
        }
    }
}
            

File: ShowImageRotator.aspx
<%@ Page Language="C#" Trace="true" %>
<%@ 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 ImageRotator</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ImageRotator
        id="ImageRotator1"
        Runat="server">
        <custom:ImageItem ImageUrl="Image1.gif" AlternateText="Image 1" />
        <custom:ImageItem ImageUrl="Image2.gif" AlternateText="Image 2" />
        <custom:ImageItem ImageUrl="Image3.gif" AlternateText="Image 3" />
    </custom:ImageRotator>
    </div>
    </form>
</body>
</html>


Item Rotator

File: ItemRotator.cs
using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ruponentModel;
namespace myControls
{
    [ParseChildren(true, "Items")]
    public class ItemRotator : CompositeControl
    {
        private ArrayList _items = new ArrayList();
        [Browsable(false)]
        public ArrayList Items
        {
            get { return _items; }
        }
        protected override void CreateChildControls()
        {
            Random rnd = new Random();
            int index = rnd.Next(_items.Count);
            Control item = (Control)_items[index];
            this.Controls.Add(item);
        }
    }
    public class Item : Control
    {
    }
}
File: Default.aspx
<%@ Page Language="C#" Trace="true" %>
<%@ 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 ItemRotator</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ItemRotator
        id="ItemRotator1"
        Runat="server">
        <custom:item ID="Item1" runat="server">
            First Item
        </custom:item>
        <custom:item ID="Item2" runat="server">
            Second Item
            <asp:Calendar
                id="Calendar1"
                Runat="server" />
        </custom:item>
        <custom:item ID="Item3" runat="server">
            Third Item
        </custom:item>
    </custom:ItemRotator>
    </div>
    </form>
</body>
</html>


Performing layout with an HTML table.

File: LoginStandards.cs
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace myControls
{
    public class LoginStandards : CompositeControl
    {
        private TextBox txtUserName;
        private TextBox txtPassword;
        public string UserName
        {
            get
            {
                EnsureChildControls();
                return txtUserName.Text;
            }
            set
            {
                EnsureChildControls();
                txtUserName.Text = value;
            }
        }
        public string Password
        {
            get
            {
                EnsureChildControls();
                return txtPassword.Text;
            }
            set
            {
                EnsureChildControls();
                txtPassword.Text = value;
            }
        }
        protected override void CreateChildControls()
        {
            txtUserName = new TextBox();
            txtUserName.ID = "txtUserName";
            this.Controls.Add(txtUserName);
            txtPassword = new TextBox();
            txtPassword.ID = "txtPassword";
            txtPassword.TextMode = TextBoxMode.Password;
            this.Controls.Add(txtPassword);
        }
        protected override void RenderContents(HtmlTextWriter writer)
        {
            writer.AddStyleAttribute("float", "left");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "3px");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.AddAttribute(HtmlTextWriterAttribute.For, txtUserName.ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Label);
            writer.Write("User Name:");
            writer.RenderEndTag();
            writer.RenderEndTag();
            writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "3px");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.AddAttribute(HtmlTextWriterAttribute.For, txtPassword.ClientID);
            writer.RenderBeginTag(HtmlTextWriterTag.Label);
            writer.Write("Password:");
            writer.RenderEndTag();
            writer.RenderEndTag();
            writer.RenderEndTag();
            writer.AddStyleAttribute("float", "left");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "3px");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            txtUserName.RenderControl(writer);
            writer.RenderEndTag();
            writer.AddStyleAttribute(HtmlTextWriterStyle.Padding, "3px");
            writer.RenderBeginTag(HtmlTextWriterTag.Div);
            txtPassword.RenderControl(writer);
            writer.RenderEndTag();
            writer.RenderEndTag();
            writer.Write("<br style="clear:left" />");
        }
        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
    }
}


Supporting Two-Way Databinding

Two-way databinding enables you to extract values from a template. 
You can use a two-way databinding expression not only to display the value of a data item, but also to update the value of a data item.
File: ProductForm.cs
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ruponentModel;
using System.Collections.Specialized;
namespace myControls
{
    public class ProductForm : CompositeControl
    {
        public event EventHandler ProductUpdated;
        private IBindableTemplate _editItemTemplate;
        private ProductFormItem _item;
        private IOrderedDictionary _results;
        public IOrderedDictionary Results
        {
            get { return _results; }
        }
        public string Name
        {
            get
            {
                EnsureChildControls();
                return _item.Name;
            }
            set
            {
                EnsureChildControls();
                _item.Name = value;
            }
        }
        public decimal Price
        {
            get
            {
                EnsureChildControls();
                return _item.Price;
            }
            set
            {
                EnsureChildControls();
                _item.Price = value;
            }
        }
        [TemplateContainer(typeof(ProductFormItem), BindingDirection.TwoWay)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        public IBindableTemplate EditItemTemplate
        {
            get { return _editItemTemplate; }
            set { _editItemTemplate = value; }
        }
        protected override void CreateChildControls()
        {
            _item = new ProductFormItem();
            _editItemTemplate.InstantiateIn(_item);
            Controls.Add(_item);
        }
        protected override bool OnBubbleEvent(object source, EventArgs args)
        {
            _results = _editItemTemplate.ExtractValues(_item);
            if (ProductUpdated != null)
                ProductUpdated(this, EventArgs.Empty);
            return true;
        }
    }
    public class ProductFormItem : WebControl, IDataItemContainer
    {
        private string _name;
        private decimal _price;
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public decimal Price
        {
            get { return _price; }
            set { _price = value; }
        }
        public object DataItem
        {
            get { return this; }
        }
        public int DataItemIndex
        {
            get { return 0; }
        }
        public int DisplayIndex
        {
            get { return 0; }
        }
    }
}
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)
        {
            ProductForm1.Name = "Laptop";
            ProductForm1.Price = 433.12m;
            ProductForm1.DataBind();
        }
    }
    protected void ProductForm1_ProductUpdated(object sender, EventArgs e)
    {
        lblName.Text = ProductForm1.Results["Name"].ToString();
        lblPrice.Text = ProductForm1.Results["Price"].ToString();
    }
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show ProductForm</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <custom:ProductForm
        id="ProductForm1"
        Runat="server" OnProductUpdated="ProductForm1_ProductUpdated">
        <EditItemTemplate>
        <asp:Label
            id="lblName"
            Text="Product Name:"
            AssociatedControlID="txtName"
            Runat="server" />
        <asp:TextBox
            id="txtName"
            Text="<%# Bind("Name") %>"
            Runat="server" />
        <br /><br />
        <asp:Label
            id="lblPrice"
            Text="Product Price:"
            AssociatedControlID="txtPrice"
            Runat="server" />
        <asp:TextBox
            id="txtPrice"
            Text="<%# Bind("Price") %>"
            Runat="server" />
        <br /><br />
        <asp:Button
            id="btnUpdate"
            Text="Update"
            Runat="server" />
        </EditItemTemplate>
    </custom:ProductForm>
    <hr />
    New Product Name:
    <asp:Label
        id="lblName"
        Runat="server" />
    <br /><br />
    New Product Price:
    <asp:Label
        id="lblPrice"
        Runat="server" />
    </div>
    </form>
</body>
</html>