当前位置:首页 > .net控件开发(七)之复合控件(1)概念基础篇

.net控件开发(七)之复合控件(1)概念基础篇

点击次数:901  更新日期:2010-12-29
\n

  复合控件是什么呢?说白了就是包含了两个或多个已存在控件的集合,复用现有的那些控件。并且来进行生成,回传处理等等。例如,复合控件就像一个团队,它包括了各种各样的人才。通过这个团队来完成所需任务(这里的生成,回传处理等)


\n

  复合控件是一个功能强大的工具,可以生成丰富复杂的组件,这些组件产生自活动对象的相互作用而不是某些字符串生成器对象的标记输出。复合控件以构成控件树的形式呈现,每个构成控件都有其自己的生命周期和事件,并且所有构成控件都联合构成一个全新的 API,并按需要尽可能地抽象化


\n

实现目的:简化控件开发,通过复合在一起,可以把许多任务委托到子控件上。就用上一例说事吧,组合团队的目的是干什么,大家都知道是为了高效的工作,集大家之所长,复合控件也如此,提高开发效率,将各个子控件的能力综合发挥。例如说。当控件包含处理回传数据控件textbox时,可以不必实现IPostBackDataHandler接口,同理,包含Button时,不必实现IPostBackEventHandler接口。


\n

实现复合控件的要点:复合控件可以派生自control类或WebControl类,但在.net2.0中通常派生于CompositeControl类,这与.net 1.x环境下开发复合控件有些不同,在.net 1.x中,复合控件必须实现INamingContainer接口,CompositeControl类表述:


\n

public abstract class CompositeControl : WebControl, INamingContainer, ICompositeControlDesignerAccessor


\n

{


\n

}


\n

CompositeControl类是一个抽象类,为自定义控件提供命名容器和控件设计器功能,该自定义包含全部子控件或使用其他控件功能。


\n

此类实现了INamingContainer接口,该接口没有任何方法,为什么要继承此接口呢?


\n

答案是:它会使页面在控件下创建一个新的命保范围,当实现该接口时,控件包含的任何子控件的表示符,保证页面中确定是唯一的。例如,如果页面上有两个gridview控件,第一个gridview的子控件和第二个gridview子控件会有不同的唯一标表示符。


\n

图例:


\n


事例:就如我们团队有一个团队号(001)[复合控件ID],个人标识(suiqi)[指子控件ID],当我们在团队的标识通常为001-suiqi


\n

开发复合控件不得不去说说两个方法,一个是CreateChildControls方法一个是EnsureChildControls方法。


\n

先说一下CreateChildControls方法:CreateChildControls方法来对子控件进行实例化、初始化、并把这些子控件添加到控件树中.


\n

但一定不能在构造器或OnInit方法中执行该逻辑. 必须在CreateChildControls方法中创建子控件,而不是在诸如实例化或初始化这样的特定阶段创建,这样可以在控件生命周期中任何需要的时候来创建子控件.当创建一个复合控件且由其子控件来处理回传数据时,这样做特别重要.


\n

再详解一下EnsureChildControls方法。该方法为了确保子控件在代码访问它们之前创建好了,该方法来创建军子控件,控件实现中的任何需要访问子控件代码必须先调用EnsureChildControls方法,例如,页面用来定位子控件的FindControl方法的默认实现,就先调用了EnsureChildControls方法.注意,如果子控件没有在控件生命周期中的预先成阶段之前被创建,那么它们会在这个时候根据要求创建.这是因为在PreRender方法的默认实现中调用了所有其Visible属性值为true的控件的EnsureChildcontrols方法。


\n

我们知道它的作用,但还要了解为什么,什么时候调用EnsureChildControls的。


\n

什么时候被调用:在PreRender过程中页面会自动调用EnsureChildControls,这个方法就会自动调用CreateChildControls方法重新建立控件内容。


\n

protected virtual void EnsureChildControls()
{
if (!this.ChildControlsCreated && !this.flags[0x100])
{

this.ChildControlsCreated = true;
}

}


\n

我们先举一个例一个,假如我们要开发一个ShowList类,它有一个字串符属性Text.我们在ShowList类中添加这样一个属性ShowTitle


\n

Private ShowList _sl;


\n

Public string ShowTitle


\n

{


\n

get{ return _sl.Text;}


\n

set{ _sl.Text=value}


\n

}


\n

当我们在CreateChildControls时实例化一个_sl时,这个代码将抛出空指针异常,这个问题是我们在设计器试图设置ShowTitle值引起的。


\n

<Yourcontrol runat=server id=”newcontrol” ShowTitle=”this will cause a null reference”/>


\n

在设计器中设置属性将在运行时被设置,也在调用CreateChildControls方法之前被调用,如果某些属性在你调用CreateChildControl之前被设置,在.net引擎将实现如下代码:


\n

YourControl newControl=new YourControl();


\n

Newcontrol.ShowTitle=”this will cause a null reference”;


\n

ParentControl.Controls.Add(newControl);


\n

在创建子控件时,任何时候被初始化,你应该在你的属性访问器中加入一条EnsureChildControls.还可以这样做:


\n

Private ShowList _sl=new ShowList();


\n

Public string ShowTitle


\n

{


\n

get{ return _sl.Text;}


\n

set{ _sl.Text=value}


\n


\n

}


\n

如果你在CreateChildControls方法,设置ShowTitle值时,这个值将有一个默认的Text 值,当创建一个控件时,加上EnsureChildControls() 确保其被创建


\n

Private ShowList _sl;
Public string ShowTitle
{
get{EnsureChildcontrols();
return _sl.Text;}
set{ EnsureChildcontrols();
_sl.Text=value}


\n

}

\n