ASP.NET Tutorial/Custom Controls/CompositeControl
Содержание
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>