[asp.net]自定义控件(支持模板)2



接着上一篇,今天来做支持数据绑定的模板控件。 使用支持数据绑定控件的一般模式为

private void Page_Load(object sender, System.EventArgs e)
{
    if(!this.IsPostBack)
    {
        this.tm.DataSource=new string[]{"one","two"};
        this.tm.DataBind();
    }
}

先指定数据源,当确认数据源正确后调用DataBind方法进行数据绑定。然后就开始调用控件自己的DataBinding事件的处理程序,一般是OnDataBinding,在这个方法里对数据源进行操作。
前面已经有文章分析了数据源,可以想到,和一般的控件不同的是,支持模板的控件在进行数据绑定时需要多做一步,除了要把数据从数据源取出,还要把这些数据绑到模板上。
还有,数据源一般都是在初次加载页面时用到,回发后就不再提供数据源,而是依靠viewstate来维持。因此“把数据绑到模板”这一步操作要放到OnDataBinding进行(因为DataBind只被使用一次),而CreateChildControls则要做一些维持状态的工作。
先要做的,是准备一个接收数据源的属性。
然后要有一个“把数据绑到模板”的方法,就像下面这个

private void createTemplate()
{
    if(this.itemTemplate!=null)
    {
        if(this.dataSource!=null)
        {
            //计算创建了多少子模板
            int itemCount=1;
            //只是为了方便而做的假设dataSource是string[]
            foreach(string text in (string[])this.dataSource)
            {
                ContainerControl cc=new ContainerControl(text);
                this.itemTemplate.InstantiateIn(cc);
                this.Controls.Add(cc);
                itemCount++;
            }
            //保存数量到ViewState
            this.ViewState["itemCount"]=itemCount;
        }
        else
            this.Controls.Add(new LiteralControl("no itemtemplate!1"));

        this.ChildControlsCreated=true;
    }
    else
        this.Controls.Add(new LiteralControl("no itemtemplate!"));
}

在上面的方法中,使用遍历数据源的方法来循环添加模板容器。不明白可以去看上一篇笔记。
viewstate可以维持模板内控件的状态,但是它却不负责创建控件,因此我们在这里保存了模板的数量itemCount,然后在CreateChildControls中创建itemCount个空模板,这样viewstate就可以给这些空模板附加上状态。

protected override void CreateChildControls()
{
    if(this.itemTemplate!=null)
    {
        int itemCount=(int)this.ViewState["itemCount"];
        for(int i=1;i<itemCount;i++)
        {
            ContainerControl cc=new ContainerControl(string.Empty);
            this.itemTemplate.InstantiateIn(cc);
            this.Controls.Add(cc);
        }
    }
    else
        this.Controls.Add(new LiteralControl("no itemtemplate!"));
    base.CreateChildControls();
}

然后就成了,下面是全部的代码。



using System;
using System.Web.UI;
using System.ComponentModel;
using System.Collections;
using System.Data;


namespace CC
{
    /// <summary>
    /// 模板练习
    /// </summary>


    //分析控件内的xml元素标记
    [ParseChildren(true)]
    public class TemplateControl : Control, INamingContainer
    {

        //模板
        private ITemplate itemTemplate;



        //指定存放模板的容器控件
        [TemplateContainer(typeof(ContainerControl)), Browsable(false)]
        public ITemplate ItemTemplate
        {
            get { return this.itemTemplate; }
            set { this.itemTemplate = value; }
        }

        //数据源
        private object dataSource;

        [Browsable(false)]
        public object DataSource
        {
            get { return this.dataSource; }
            set { this.dataSource = value; }
        }

        /// <summary>
        /// 创建子控件,在这里创建的只是空壳,其内容根据ViewState来填充
        /// </summary>
        protected override void CreateChildControls()
        {
            if (this.itemTemplate != null)
            {
                int itemCount = (int)this.ViewState["itemCount"];
                for (int i = 1; i < itemCount; i++)
                {
                    ContainerControl cc = new ContainerControl(string.Empty);
                    //将模板添加到专门的容器中
                    this.itemTemplate.InstantiateIn(cc);
                    //将容器加到父控件中
                    this.Controls.Add(cc);
                }
            }
            else
                this.Controls.Add(new LiteralControl("no itemtemplate!"));

            base.CreateChildControls();
        }

        /// <summary>
        /// 当用户端调用DataBind,则表示准备好了数据源,此时可以开始创建子模板
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDataBinding(EventArgs e)
        {
            //确定服务器控件是否包含子控件。如果不包含,则创建子控件。
            //this.EnsureChildControls();
            this.createTemplate();
            base.OnDataBinding(e);
        }



        //手动创建子模板
        private void createTemplate()
        {
            if (this.itemTemplate != null)
            {
                //当由类实现时,定义子控件和模板所属的 Control 对象。然后在内联模板中定义这些子控件
                //this.itemTemplate.InstantiateIn(this);
                if (this.dataSource != null)
                {
                    //计算创建了多少子模板
                    int itemCount = 1;
                    //只是为了方便而做的假设dataSource是string[]
                    foreach (string text in (string[])this.dataSource)
                    {
                        ContainerControl cc = new ContainerControl(text);
                        //将模板添加到专门的容器中
                        this.itemTemplate.InstantiateIn(cc);
                        //将容器加到父控件中
                        this.Controls.Add(cc);
                        itemCount++;
                    }
                    //保存数量到ViewState
                    this.ViewState["itemCount"] = itemCount;
                }
                else
                    this.Controls.Add(new LiteralControl("no itemtemplate!1"));
                //确认子模板创建完毕
                this.ChildControlsCreated = true;
            }
            else
                this.Controls.Add(new LiteralControl("no itemtemplate!"));
        }
    }



    /// <summary>
    /// 容器控件,用来存放模板
    /// </summary>
    public class ContainerControl : Control, INamingContainer
    {
        private string text;
        public string Text
        {
            get { return this.text; }
        }
        public ContainerControl(string text)
        {
            this.text = text;
        }
    }


}







完成了这个,接下来我们就可以自己写一个Repeater控件!






本文转载:CSDN博客