asp.net控件開發基礎(16) --------服務器模板控件

  上一篇說要對以前進行補充,那個補充就先留着吧.寫總結比較累,所以這篇爲第16篇,第15篇先留着

這次我們繼續討論.主題是模板控件,模板控件將是複雜控件的起步

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綁定語法,如上面的幾個例子.大家可以測試一下.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章