当表现控件触发databinding事件,分页控件就可以获取datasource属性。遗憾的是,微软没有提供所 有数据绑定类实现的接口,诸如idatasourceprovider之类,而且并非所有从control或webcontrol类继承的控件都有一个 datasource属性,因此向上定型成control类没有意义,唯一可行的办法是通过reflection api直接操作datasoruce属性。在讨论事件句柄方法之前,应该指出的是,为了注册事件句柄,首先必须获得一个表现控件的引用。分页控件显露了一 个简单的字符串属性bindtocontrol:
public string bindtocontrol
{
get
{
if (_bindcontrol == null)
throw new nullreferenceexception("在使用分页控件之前,请先通过设置bindtocontrol属性绑定到一个控件。");
return _bindcontrol;}
set{_bindcontrol=value;}
}
这个方法非常重要,所以最好能够抛出一个含义更明确的信息,而不是抛出标准的nullreferenceexception异常。在分页控件的 oninit方法中,我们解析了对表现控件的引用。本例应当用oninit事件句柄(而不是构造函数)来确保jit编译的aspx页面已经设置了 bindtocontrol。
protected override void oninit(eventargs e)
{
_boundcontrol = parent.findcontrol(bindtocontrol);
boundcontrol.databinding += new eventhandler(boundcontrol_databound);
base.oninit(e);
...
}
搜索表现控件的操作通过搜索分页控件的parent控件完成,在这里,parent就是页面本身。按照这种方式使用parent比较危险,举例来说,如 果分页控件嵌入到了另一个控件之中,例如嵌入到了table控件之中,则parent引用实际上将是一个对table控件的引用。由于 findcontrol方法只搜索当前的控件集合,除非表现控件就在该集合之中,否则不可能搜索到。一种比较安全的方法是递归地搜索各个控件集合,直至找 到目标控件为止。
找到boundcontrol之后,我们将分页控件注册成为databinding事件的监听器。由于分页控件要操作数 据源,所以该事件句柄应当是调用链中的最后一个,这一点很重要。不过,只要表现控件在oninit事件句柄中注册databinding的事件句柄(默认 行为),分页控件操作数据源时就不会出现问题。
databound事件句柄负责获取表现控件的datasource属性。
private void boundcontrol_databound(object sender,system.eventargs e)
{
if (hasparentcontrolcalleddatabinding) return;
type type = sender.gettype();
_datasource = type.getproperty("datasource");
if (_datasource == null)
throw new notsupportedexception("分页控件要求表现控件必需包含一个datasource。");
object data = _datasource.getgetmethod().invoke(sender,null);
_builder = adapters[data.gettype()];
if (_builder == null)
throw new nullreferenceexception("没有安装适当的适配器来处理下面的数据源类型:"+data.gettype());
_builder.source = data;
applydatasensitivityrules();
bindparent();
raiseevent(dataupdate,this);
}
在databound中,我们尝试通过reflection api获得datasource属性,然后返回实际数据源的一个引用。现在虽然已经获知了数据源,但分页控件还必须知道如何操作该数据源。为了让分页控件 不依赖于特定的表现控件,问题复杂了很多。不过,如果让分页控件依赖于特定的数据源,那就背离了设计一个灵活的分页控件的目标。我们要通过一个接插式的体 系结构来确保分页控件能够处理各种数据源,无论是.net提供的数据源,还是自定义的数据源。
为了提供一个健壮的、可伸缩的接插式体系结构,我们将利用[gof] builder模式构造出一个解决方案。

idatasourceadapter接口定义了分页控件操作数据所需的最基本的元素,相当于“插头”。
publicinterface idatasourceadapter
{
int totalcount{get;}
object getpageddata(int start,int end);
}
totalcount属性返回在处理数据之前数据源所包含元素的总数,而getpageddata方法返回原始数据的一个子集,例如:假设数据源是一个 包含20个元素的数组,分页控件将数据显示成每页10个元素,则第一页的元素子集是数组元素0-9,第二页的元素子集是数组元素10-19。 dataviewadapter提供了一个dataview类型的插头:
internal class dataviewadapter:idatasourceadapter
{
private dataview _view;
internal dataviewadapter(dataview view)
{
_view = view;
}
public int totalcount
{
get{return (_view == null) ? 0 : _view.table.rows.count;}
}
public object getpageddata(int start, int end)
{
datatable table = _view.table.clone();
for (int i = start;i<=end && i<= totalcount;i++)
{
table.importrow(_view[i-1].row);
}
return table;
}
}
dataviewadapter实现了idatasourceadapter的getpageddata方法,该getpageddata克隆原始的 datatable,将原始datatable中的数据导入到新的datatable。该类的可见性有意地设置成internal,目的是为了向web开 发者隐藏实现细节,进而通过builder类提供一个更简单的接口。
public abstract class adapterbuilder
{
private object _source;
private void checkfornull()
{
if (_source == null) throw new nullreferenceexception("必须提供一个合法的数据源");
}
public virtual object source
{
get
{
checkfornull();
return _source;}
set
{
_source = value;
checkfornull();
}
}
public abstract idatasourceadapter adapter{get;}
}
adapterbuilder抽象类为idatasourceadapter类型提供了一个更容易管理的接口,由于提高了抽象程度,我们不必再直接使用 idatasourceadapter,同时adapterbuilder还提供了在分页数据之前执行预处理的指令。另外,该builder还使得实际的 实现类,例如dataviewadapter,对分页控件的用户透明:
public class datatableadapterbuilder:adapterbuilder
{
private dataviewadapter _adapter;
private dataviewadapter viewadapter
{
get
{
if (_adapter == null)
{
datatable table = (datatable)source;
_adapter = new dataviewadapter(table.defaultview);
}
return _adapter;
}
}
public override idatasourceadapter adapter
{
get
{
return viewadapter;
}
}
}
public class dataviewadapterbuilder:adapterbuilder
{
private dataviewadapter _adapter;
private dataviewadapter viewadapter
{
get
{ // 延迟实例化
if (_adapter == null)
{
_adapter = new dataviewadapter((dataview)source);
}
return _adapter;
}
}
public override idatasourceadapter adapter
{
get{return viewadapter;}
}
}
文章整理:站长天空 网址:http://www.z6688.com/
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!




