一起谈.NET技术,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.net控件开发基础(15)

下一篇:asp.net控件开发基础(17)

时间: 2024-10-29 19:56:28

一起谈.NET技术,asp.net控件开发基础(16)的相关文章

ASP.NET控件开发基础(16)

上一篇说要对以前进行补充,那个补充就先留着吧.写总结比较累,所以这篇为第16篇,第15篇先留着 这次我们继续讨论.主题是模板控件,模板控件将是复杂控件的起步 1.asp.net内置的模板控件,了解模板控件 如下图,以下为asp.net内置的模板控件 开发基础(16)-"> 上图的控件一方面是模板控件,另一方面又是数据绑定控件.这里我们暂且不讨论如何实现数据绑定. 使用上面控件的话,应该熟悉控件存在着不同的模板,如下图Repeater控件的模板类型. 在不同模板内你可以定义控件显示内容会呈现

一起谈.NET技术,asp.net控件开发基础(15)

继续我们的话题吧.自定义控件.如果你还不熟悉自定义控件开发的话,还请看看我以前写了几篇,希望对你有帮助 1.1何处继承 自定义控件一般从以下几个基类(此处不包含数据控件) 一.Control类(所有服务器控件的基类,算是比较底层的类,如果控件功能比较简单,要求不多,可直接继承此类.) 二.WebControl类(标准控件的基类,继承此类,你可以继承其丰富的公共属性,若标准控件中的控件没有你需要的控件,你可以继承此类) 三.CompositeControl 类(2.0新增的类,此类继承自WebCo

一起谈.NET技术,asp.net控件开发基础(17)

本篇将开始介绍如自定义数据绑定控件,这里感谢很多人的支持,有你们的支持很高兴.这里首先需要大家熟悉asp.net模板控件的使用,还有自定义模板控件.因为数据绑定控件多是基于模板控件的. 一.回顾 如果你使用过asp.net内置的数据控件(如DataList,Repeater),你一定会这么做 1.设置数据源 DataSource属性 2.调用数据绑定  DataBind方法 3.在控件的不同模板内使用绑定语法显示数据 这三步应该是必须要做的 其他更多的 你可能需要对绑定的数据进行统一的一些操作(

一起谈.NET技术,asp.net控件开发基础(13)

1.减轻服务器压力,增加用户体验 服务器功能是强大的,客户端脚本一点也不弱,现在的ajax技术和Atlas技术就是最好的证明,我们总是期待UI有一个好的效果,flash动画给我们带来了很酷的效果,我们至少也可以为我们的服务器控件添加客户端脚本,一方面减少了服务器端的回传,一方面又能为控件提供非常酷的效果.我想我们都很喜欢ATLAS里面很多很酷的控件吧,而且无刷新,服务器控件与客户端脚本交互使用,那会服务器控件变的更加完美. 经过上面的废话,下面我们进入正题 2.简单为服务器控件添加客户端脚本 我

一起谈.NET技术,asp.net控件开发基础(8)

有一些复合控件直接把按钮触发事件所需的事情封装好,另外一种则是自定义事件,更具灵活性,当然这是根据需要设计的.以下会以例子来说明的.下面我们假设我们控件中有两个按钮.以下不列出所有代码,具体可在文章最后下载代码. (1) 直接实现按钮事件 在控件中(以下代码并非实现复合控件)直接实现事件则无需自定义事件,如下代码(如果对数据回传有些不熟悉的话,可先看第三篇,希望对你有帮助) 示例一(只列出局部代码,具体可在文章最后下载代码) void IPostBackEventHandler.RaisePos

一起谈.NET技术,asp.net控件开发基础(2)

或许大家还对为何要重写Render方法存有疑惑,希望大家看看我举的例子,能够明白Render方法和其他两个方法的作用,然后真正明白为何一般情况下只须重写Render方法.我们知道我们每次编写控件时,都需要重写Render方法,我们发现在Control类中很多方法可以重写,但我们没有去重写他们,我们需要遵循一个原则,在需要重载的时候再去重写他们 我们还是先来看看与Render方法相关的两个方法 //RenderControl方法的基本实现 public void RenderControl(Htm

一起谈.NET技术,asp.net控件开发基础(22)

上两篇讨论了如何定义结合数据源控件的数据绑定控件.这次我们一起来看下数据源控件是如何实现的.asp.net2.0已经为我们提供了很多数据源控件,相信大家都用过了,也希望大家对其有所熟悉.关于它能做什么就不说了.下面我们也一起来看看,如何简单的实现. 一.你必须了解的 1.关于数据源控件(DataSourceControl) 虽然表面看来,给数据绑定控件指定DataSourceID属性,数据源控件帮你做了一切工作,其实不然,数据源控件只负责收集与数据交互的相关信息,如:SqlDataSource的

一起谈.NET技术,asp.net控件开发基础(18)

本篇继续上篇的讨论,可能大家已经在使用asp.net2.0了,DataSource属性不再使用,而是跟数据源控件搭配使用.现在讨论的绑定技术都是基于1.1版本,先熟悉一下,本质上是一样的,这样一步步的学习.对以后绝对有帮助.因为当你使用数据源控件,只需要设置一个DataSourceID,方便的同时你是否知道数据源控件帮你做了什么事情,如果你想觉的够用了,可以不用了解,但我相信你一定会有需求.上篇最后说过了,讨论还刚刚开始,我们大致把核心的方法都写出来了.下面我们继续. 一.控件对比 我们可以使用

一起谈.NET技术,asp.net控件开发基础(10)

集合属性相信大家都很熟悉也很常用,如DropDownList,ListBox等控件 <asp:DropDownList ID="DropDownList1" runat="server">            <asp:ListItem>测试1</asp:ListItem>            <asp:ListItem>测试2</asp:ListItem>            <asp:Lis