自定义控件(支持模板)

自定义控件(支持模板)
自定义控件(支持模板)

自定义控件(支持模板)

再说一下,这部分内容最好的教材就是我一开始推荐的那个视频材料。如果还有没有下的那就赶快去下~~指不定哪天微软的网站被攻击,倒闭了,就没的下了。不过话说回来,如果微软都倒闭了,那我们还学.net干嘛啊~~~

不瞎扯了,下面转入正题。

任何控件都可以包含子控件。一个控件支持模板,其实就是在往它里面加子控件。模板是用什么形式在控件内公开的呢?想一想,我们用一个一般的控件都可以直接用标记来指定属性,而模板也是使用标记来操作。使用模板的时候,就是用标记的方法给模板赋值,根据“任何控件都可以包含子控件”,所以模板里也可以再包含控件。因此,模板在控件定义中就表现为属性。我们的标记都是用xml形式呈现的,因此,使用模板实际上就是给控件的某个属性赋于xml标记这样的值。

上面的话是否可以看懂呢?看下面的这段标记。


hello world !

这是一个支持模板及数据绑定的自定义控件。它是这样完成的。

ITEMTEMPLATE是一个ITemplate类型的属性,只要对外公开了此属性,就可以使控件支持模板。

//模板

private ITemplate itemTemplate;

public ITemplate ItemTemplate

{

get{ return this.itemTemplate; }

set{ this.itemTemplate=value; }

}

设置好属性后,还需要给控件加一个类级别的[ParseChildren(true)]特性,用来指明将控件内的XML标记元素视为属性处理,这样就可以在标签内定义自己的模板。

作完这些后,下一步需要做的就是要将模板做为子控件加入到控件中。

protected override void CreateChildControls()

{

if(this.itemTemplate!=null)

{

//当由类实现时,定义子控件和模板所属的 Control 对象。然后在内联模板中定义这些子控件。

//这里把容器控件指定为代表控件本身的this

this.itemTemplate.InstantiateIn(this);

}

else

this.Controls.Add(new LiteralControl("no itemtemplate!"));

base.CreateChildControls();

}

通过重写CreateChildControls方法来完成。

只有调用DataBind,才可能将数据绑定到子控件。因此我们还需要重写OnDataBinding protected override void OnDataBinding(EventArgs e)

{

//确定服务器控件是否包含子控件。如果不包含,则创建子控件。

this.EnsureChildControls();

base.OnDataBinding (e);

}

到这里,一个简单的支持模板的控件就算完成了,可以自己把上面的东西组合起来看看效果。我们需要模板一般都是要进行数据绑定的,接下来看看怎么实现。

<%# Container.Text%>

上面是一般的绑定表达式,可以看到,其实就是调用了一个对象的属性,其中Container用来表示乘放模板的容器,而Text正是该容器的属性。

一般用TemplateContainer特性来指定容器的类型,像这样:

[TemplateContainer(typeof(ContainerControl)),Browsable(false)]

public ITemplate ItemTemplate

{ //... }

ContainerControl就是一个容器控件,其定义如下

public class ContainerControl : Control,INamingContainer

{

private string text;

public string Text

{

get{ return this.text; }

}

public ContainerControl(string text)

{

this.text=text;

}

}

注意,这是一个控件,只是没有向页面呈现而已。实际上,它的作用就是用来乘放模板。这样,我们创建模板时就改成了这样子

ContainerControl cc=new ContainerControl(text);

this.itemTemplate.InstantiateIn(cc);

this.Controls.Add(cc);

下面是这个控件的完整的代码:)

using System;

using System.Web.UI;

using https://www.360docs.net/doc/9f13801394.html,ponentModel;

namespace CC

{

///

/// 模板练习

///

//分析控件内的xml元素标记

[ParseChildren(true)]

public class SimpleTemplate : Control,INamingContainer

{

//模板

private ITemplate itemTemplate;

//指定存放模板的容器控件

[TemplateContainer(typeof(ContainerControl)),Browsable(false)] public ITemplate ItemTemplate

{

get{ return this.itemTemplate; }

set{ this.itemTemplate=value; }

}

//辅助进行绑定的属性

private string text;

public string Text

{

get{ return this.text; }

set{ this.text=value; }

}

///

/// 创建子控件

///

protected override void CreateChildControls()

{

if(this.itemTemplate!=null)

//使用得到的属性来创建容器控件

ContainerControl cc=new ContainerControl(this.text);

//将模板添加到专门的容器中

this.itemTemplate.InstantiateIn(cc);

//将容器加到父控件中

this.Controls.Add(cc);

}

else

this.Controls.Add(new LiteralControl("no itemtemplate!"));

base.CreateChildControls();

}

///

/// 在这里进行检查并创建模板

///

///

protected override void OnDataBinding(EventArgs e)

{

//确定服务器控件是否包含子控件。如果不包含,则创建子控件。

this.EnsureChildControls();

base.OnDataBinding (e);

}

}

}

具体使用的页面,.aspx页上的标记就像我们一开始那样,.cs里的代码为

if(!this.IsPostBack)

{

this.tem.Text="hello world !";

this.tem.DataBind();

}

在这里,就算postback了,显示的页面还是没有改变,这主要是因为模板内的控件各自维持自己的状态,了解这一点很重要,因为接下来支持数据绑定时需要使用这一点。

还有一点,如果把DataBind注释掉了,那Text就不会绑定到模板上。你可以实验一下把EnsureChildControls放到其他方法中(比如Render什么的),结果都是如此。

使用支持数据绑定控件的一般模式为

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

{

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 https://www.360docs.net/doc/9f13801394.html,ponentModel;

using System.Collections;

using System.Data;

namespace CC

{

///

/// 模板练习

///

//分析控件内的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; }

}

///

/// 创建子控件,在这里创建的只是空壳,其内容根据ViewState来填充

///

protected override void CreateChildControls()

{

if(this.itemTemplate!=null)

{

int itemCount=(int)this.ViewState["itemCount"];

for(int i=1;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();

}

///

/// 当用户端调用DataBind,则表示准备好了数据源,此时可以开始创建子模板///

///

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!"));

}

}

///

/// 容器控件,用来存放模板

///

public class ContainerControl : Control,INamingContainer

{

项目软件设计规格说明书模板

附件三 XXX项目 软件设计规格说明书 版本 <>

目录 1概述.............................................. 错误!未定义书签。 编写目的........................................ 错误!未定义书签。 编写依据........................................ 错误!未定义书签。 术语和缩略词.................................... 错误!未定义书签。2软件概要.......................................... 错误!未定义书签。 软件总体描述.................................... 错误!未定义书签。 软件设计约束及有关说明.......................... 错误!未定义书签。 使用者特点...................................... 错误!未定义书签。3开发和运行环境.................................... 错误!未定义书签。 硬件环境........................................ 错误!未定义书签。 支持软件环境.................................... 错误!未定义书签。 接口............................................ 错误!未定义书签。 控制和操作...................................... 错误!未定义书签。4详细需求.......................................... 错误!未定义书签。 性能需求........................................ 错误!未定义书签。 功能需求........................................ 错误!未定义书签。 数据需求........................................ 错误!未定义书签。5故障处理需求...................................... 错误!未定义书签。 软件运行故障.................................... 错误!未定义书签。 软件使用故障.................................... 错误!未定义书签。6质量需求.......................................... 错误!未定义书签。7其他需求.......................................... 错误!未定义书签。 易用性需求...................................... 错误!未定义书签。 安全性需求...................................... 错误!未定义书签。

wpf自定义slider控件

自定义Slider控件 最终效果: 界面: