asp.net控件开发基础(16) --------服务器模板控件

这次我们继续讨论.主题是模板控件,模板控件将是复杂控件的起步

1.asp.net内置的模板控件,了解模板控件

如下图,以下为asp.net内置的模板控件



上图的控件一方面是模板控件,另一方面又是数据绑定控件.这里我们暂且不讨论如何实现数据绑定.

使用上面控件的话,应该熟悉控件存在着不同的模板,如下图Repeater控件的模板类型.



在不同模板内你可以定义控件显示内容会呈现不同效果.典型的运用就是GridView,其呈现代码会是一个表格代码,而Repeater则是自定义的.其实其是内部已经实现了的,暂且先不管这些.下面一步步看下来如何实现.


2.实现模板控件

2.1简单实现模板控件(静态模板)

(1)模板控件为特殊的复合控件
,你还是需要实现INamingContainer接口,因为在模板属性的内容是为子控件集合添加到模板控件中,为保证控件具有唯一标识符.其实现将在CreateChildControls方法中创建子控件.

asp.net2.0中可以直接继续CompositeControl就可

(2)定义控件属性

模板属性为System.Web.UI. ITemplate 接口,此接口有一InstantiateIn 方法 将在下面分析

上一篇我们说明了控件内部属性和控件的区别,模板并非控件而是属性,我们在属性浏览器中并未看到此属性,是因为我们为其加了元数据,作为内部属性使用

定义模板属性方法如下

         // 声明变量
         private  ITemplate _itemTemplate;


        
// 属性
        [Browsable( false )]
        [TemplateContainer(
typeof (Article))]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        
public  ITemplate ItemTemplate
        
{
            
get return _itemTemplate; }
            
set { _itemTemplate = value; }
        }

这里我们认识到了一个TemplateContainer元数据,其与容器控件关联起来.Article为默认其自身控件,即默认将自身控件作为容器控件.

(3).重写CreateChildControls方法

此方法我们以前已认识过了,主要是为控件添加子控件

         protected   override   void  CreateChildControls()
        
{
            _itemTemplate.InstantiateIn(
this);
        }


这次我们要做的重点是认识ITemplate接口的InstantiateIn 方法,方法有一个Control参数,其为子控件和模板定义了一个容器控件(此处为其自身控件,下面看页面代码).如GridView和DataList控件都实现了自定义的容器控件.Repeater则是完全自定义的.这里暂且默认实现

实现代码

在模板内拖了一个label控件

     < custom:Article
        
id ="Article1"
        Runat
="server" >
        
< ItemTemplate >
        
< asp:Label  ID ="Label1"  runat ="server"  Text ="Label" ></ asp:Label >
        
</ ItemTemplate >
    
</ custom:Article >    

OK,你可以看一下效果了,当然你可以定义多个模板然后在多个不同模板内添加内容.我们来看下其控件树内容,如下图



子控件有一个Label控件,非控件内容则以LiteralControl呈现.

2.2实现动态模板

当我们使用DataList控件时,往往在模板中动态的绑定一些数据,获取的这些数据则是ITemplate接口的InstantiateIn 方法中的容器控件.下面我们为控件定义属性,然后通过DataBind()方法和数据绑定表达式获取数据

我们先先定义三个属性

页面代码,注意要用DataBind()方法

     void  Page_Load()
    
{
        Article1.Title 
= "Creating Templated Databound Controls";
        Article1.Author 
= "Stephen Walther";
        Article1.Contents 
= "Blah, blah, blah, blah";
        Article1.DataBind();
    }

通过Container数据绑定表达式获取容器对象属性,此处容器对象为默认的Article



如下实现

     < custom:Article
        
id ="Article1"
        Runat
="server" >
        
< ItemTemplate >
        
< asp:Label  ID ="Label1"  runat ="server"  Text ="Label" ></ asp:Label >
        
<% # Container.Title %> < br  />
        
<% # Container.Author  %> < br  />
        
<% # Container.Contents  %> < br  />
        
</ ItemTemplate >
    
</ custom:Article >  

好了,到这里你就实现了一个简单的动态模板控件了.

2.3实现默认模板

在购书网站上我们常常看到由于图书太多的情况下,管理人员未能将图书封面发布到网站上,这时此书可能出现默认的图片"尚为此书添加图书封面"

在一个具有模板的控件里,如果你未为控件添加模板属性的话,你可以通过实现默认模板来实现默认效果.

(1)那你第一步要做的就是定义一个自定义模板.此模板需要实现ITemplate接口,实现InstantiateIn方法.看一下典型实现,如下代码

     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;
        }


    }

在InstantiateIn方法中,定义了默认控件,并实现了 默认绑定.在各自的数据绑定事件里通过容器控件( 默认容器控件为ArticleWithDefault,此处还是没自定义容器控件,下面会介绍)的NamingContainer属性获取控件ID值.然后对控件进行赋值.

(2)重写CreateChildControls方法

当未定义模板属性时,则实现默认模板

         protected   override   void  CreateChildControls()
        
{
            
if (_itemTemplate == null)
                _itemTemplate 
= new ArticleDefaultTemplate();
            _itemTemplate.InstantiateIn(
this);
        }

(3)页面代码

下面实现效果跟2.2的定义的模板控件效果一样,这里只为说明默认模板的使用方法

    void Page_Load()
    {
        ArticleWithDefault1.Title = "Creating Templated Databound Controls";
        ArticleWithDefault1.Author = "Stephen Walther";
        ArticleWithDefault1.Contents = "Blah, blah, blah, blah";
        ArticleWithDefault1.DataBind();
    }

    
< custom:ArticleWithDefault
        
id ="ArticleWithDefault1"
        Runat
="server"   />

2.4实现自定义容器控件

上面我已经多次注明容器控件为默认自身控件,你可以通过自定义容器控件

GridView控件会自动把数据以表格形式呈现,DataList控件有 DataListItem , Repeater则有RepeaterItem.

这些控件实现数据绑定后,通常不是显示一条数据的,其控件都有一个Items属性,其表示项集合.

每项数据都在其Item里面,看一下DataList绑定数据以后的控件树



我们常常会需要在模板控件里以以下方式来获取模板内部控件

如在DataList控件中

     protected   void  DataList1_ItemDataBound( object  sender, DataListItemEventArgs e)
    
{
        e.Item.FindControl(
"");
        DataList1.Items[
0].BackColor = System.Drawing.Color.Red;
    }


通过此方法我们可以处理一些特殊的列和行.为实现上面效果,我们也可以为模板控件自定义容器控件

(1)自定义容器控件类

注意需要实现IDataItemContainer接口,就如DataList一样,其绑定的数据不可能是一条的.


   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; }
        }

    }

然后在主控件中如下实现


      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;
            }

        }


(2)用TemplateContainer与模板属性关联起来

        [TemplateContainer( typeof (ProductItem))]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        
public  ITemplate ItemTemplate
        
{
            
get return _itemTemplate; }
            
set { _itemTemplate = value; }
        }

(3)重写CreateChildControls方法

注意了,此处模板的InstantiateIn方法不再是this了,而是自定义容器控件了,再用数据绑定表达式访问的将是ProductItem的数据(即自定义容器控件的数据)

         protected   override   void  CreateChildControls()
        
{
            _item 
= new ProductItem();
            _itemTemplate.InstantiateIn(_item);
            Controls.Add(_item);
        }

(4)页面代码

     void  Page_Load()
    
{
        Product1.Name 
= "Laptop Computer";
        Product1.Price 
= 1254.12m;
        Product1.DataBind();
    }


    
< custom:Product
        id
= " Product1 "
        Runat
= " Server " >
        
< ItemTemplate >
       
        Name: 
<% # Eval( " Name " %>
        
< br  />
        Price: 
<% # Eval( " Price " " {0:c} " %>  
        
</ ItemTemplate >     
    
</ custom:Product >


上面以Eval来绑定数据,也可以用Container表达式,如下图,其类型为 ProductItem




注意:当不是数据绑定控件时,则不能用Eval绑定语法,如上面的几个例子.大家可以测试一下.

好了本次该讲的我想也讲完了,以上代码多为asp.net2.0揭密的例子

本来上面代码完全可以在一个控件中实现的,但我把其分开来讨论,这样理解的更加深刻.上面都是模板控件基础.将为以后实现复杂效果打下基础.本次未涉及到数据绑定,下次我们继续讨论.希望对你有帮助,错误之处还请提出.
 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值