ASP.NET Tutorial/Custom Controls/CompositeControl
Содержание
Building Composite Controls
<source lang="csharp">
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">
<asp:Label ID="lblUserName" Text="User Name:" AssociatedControlID="txtUserName" Runat="server" /> <custom:RequiredTextBox ID="txtUserName" Runat="Server" />
<asp:Button ID="btnSubmit" Text="Submit" Runat="server" OnClick="btnSubmit_Click" />
<asp:Label id="lblResults" Runat="server" />
</form>
</body> </html></source>
Building Hybrid Controls
<source lang="csharp">
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; } } }
}</source>
Creating a Default Template
<source lang="csharp">
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("
")); container.Controls.Add(lblAuthor); container.Controls.Add(new LiteralControl("
")); 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">
<custom:ArticleWithDefault id="ArticleWithDefault1" Runat="server" />
</form>
</body> </html></source>
Creating Templated Databound Controls
<source lang="csharp">
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">
<custom:DivView id="lstProducts" DataSourceID="srcProducts" CssClass="products" Runat="Server"> <ItemTemplate>
<%# Eval("Title") %>
Director: <%# Eval("Director") %> </ItemTemplate> </custom:DivView>
<asp:SqlDataSource id="srcProducts" ConnectionString="<%$ ConnectionStrings:Products %>" SelectCommand="SELECT Title, Director FROM Products" Runat="server" />
<asp:LinkButton id="lnkReload" Text="Reload" Runat="server" />
</form>
</body> </html></source>
File: Product.cs
<source lang="csharp">
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">
<custom:Product id="Product1" Runat="Server"> <ItemTemplate> Name: <%# Eval("Name") %>
Price: <%# Eval("Price", "{0:c}") %> </ItemTemplate> </custom:Product>
</form>
</body> </html></source>
Image Rotator
<source lang="csharp">
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">
<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>
</form>
</body> </html></source>
Item Rotator
<source lang="csharp">
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">
<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>
</form>
</body> </html></source>
Performing layout with an HTML table.
<source lang="csharp">
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("
"); } protected override HtmlTextWriterTag TagKey { get { return HtmlTextWriterTag.Div; } } }
}</source>
Supporting Two-Way Databinding
<source lang="csharp">
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">
<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" />
<asp:Label id="lblPrice" Text="Product Price:" AssociatedControlID="txtPrice" Runat="server" /> <asp:TextBox id="txtPrice" Text="<%# Bind("Price") %>" Runat="server" />
<asp:Button id="btnUpdate" Text="Update" Runat="server" /> </EditItemTemplate> </custom:ProductForm>
New Product Name: <asp:Label id="lblName" Runat="server" />
New Product Price: <asp:Label id="lblPrice" Runat="server" />
</form>
</body> </html></source>