一个相当独立的.通用分页控件c#源码三(downmoon收集)

DataView类型和DataTable类型的关系是如此密切,所以构造一个通用性的DataAdapter可能是有意义的,其实只要加入另一个处 理DataTable的构造函数就足够了。遗憾的是,当用户需要不同的功能来处理某个DataTable时,就必须替换或继承整个类。如果我们构造一个使 用同一IdataSourceAdapter的新Builder,用户在选择如何实现适配器时就拥有更多的*。

  在分页控件中,寻找适当Builder类的操作由一个类型安全的集合完成。

一个相当独立的.通用分页控件c#源码三(downmoon收集)public class AdapterCollection:DictionaryBase
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)
private string GetKey(Typekey)
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)
return key.FullName;
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
public AdapterCollection() ... {}
一个相当独立的.通用分页控件c#源码三(downmoon收集) publicvoidAdd(Typekey,AdapterBuildervalue)
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集) Dictionary.Add(GetKey(key),value);
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集) publicboolContains(Typekey)
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)
return Dictionary.Contains(GetKey(key));
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集) publicvoidRemove(Typekey)
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集) Dictionary.Remove(GetKey(key));
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)
public AdapterBuilder this [Typekey]
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
get ... { return (AdapterBuilder)Dictionary[GetKey(key)];}
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
set ... {Dictionary[GetKey(key)] = value;}
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)


   AdapterCollection依赖于DataSource类型,DataSource通过BoundControl_DataBound巧妙地引 入。这里使用的索引键是Type.FullName方法,确保了每一种类型索引键的唯一性,同时这也把保证每一种类型只有一个Builder的责任赋予了 AdapterCollection。将Builder查找加入BoundControl_DataBound方法,结果如下:

一个相当独立的.通用分页控件c#源码三(downmoon收集)public AdapterCollectionAdapters
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
get ... { return _adapters;}
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)
一个相当独立的.通用分页控件c#源码三(downmoon收集)
private bool HasParentControlCalledDataBinding
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
get ... { return _builder != null ;}
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)
一个相当独立的.通用分页控件c#源码三(downmoon收集)
private void BoundControl_DataBound( object sender,System.EventArgse)
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)
if (HasParentControlCalledDataBinding) return ;
一个相当独立的.通用分页控件c#源码三(downmoon收集) Typetype
= sender.GetType();
一个相当独立的.通用分页控件c#源码三(downmoon收集) _datasource
= type.GetProperty( " DataSource " );
一个相当独立的.通用分页控件c#源码三(downmoon收集)
if (_datasource == null )
一个相当独立的.通用分页控件c#源码三(downmoon收集)
throw new NotSupportedException( " 分页控件要求表现控件必需包含一个DataSource。 " );
一个相当独立的.通用分页控件c#源码三(downmoon收集)
object data = _datasource.GetGetMethod().Invoke(sender, null );
一个相当独立的.通用分页控件c#源码三(downmoon收集) _builder
= Adapters[data.GetType()];
一个相当独立的.通用分页控件c#源码三(downmoon收集)
if (_builder == null )
一个相当独立的.通用分页控件c#源码三(downmoon收集)
throw new NullReferenceException( " 没有安装适当的适配器来处理下面的数据源类型: " + data.GetType());
一个相当独立的.通用分页控件c#源码三(downmoon收集) _builder.Source
= data;
一个相当独立的.通用分页控件c#源码三(downmoon收集)
一个相当独立的.通用分页控件c#源码三(downmoon收集) ApplyDataSensitivityRules();
一个相当独立的.通用分页控件c#源码三(downmoon收集) BindParent();
一个相当独立的.通用分页控件c#源码三(downmoon收集) RaiseEvent(DataUpdate,
this );
一个相当独立的.通用分页控件c#源码三(downmoon收集) }



  BoundControl_DataBound方法利用HasParentControlCalledDataBinding检查是否已经创建了Builder,如果是,则不再执行寻找适当Builder的操作。Adapters表的初始化在构造函数中完成:

一个相当独立的.通用分页控件c#源码三(downmoon收集)public Pager()
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集) SelectedPager
= new System.Web.UI.WebControls.Style();
一个相当独立的.通用分页控件c#源码三(downmoon收集) UnselectedPager
= new System.Web.UI.WebControls.Style();
一个相当独立的.通用分页控件c#源码三(downmoon收集) _adapters
= new AdapterCollection();
一个相当独立的.通用分页控件c#源码三(downmoon收集) _adapters.Add(
typeof (DataTable), new DataTableAdapterBuilder());
一个相当独立的.通用分页控件c#源码三(downmoon收集) _adapters.Add(
typeof (DataView), new DataViewAdapterBuilder());
一个相当独立的.通用分页控件c#源码三(downmoon收集) }



  最后一个要实现的方法是BindParent,用来处理和返回数据。

一个相当独立的.通用分页控件c#源码三(downmoon收集)private void BindParent()
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集) _datasource.GetSetMethod().Invoke(BoundControl,
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
new object [] ... {_builder.Adapter.GetPagedData(StartRow,ResultsToShow * CurrentPage)} );
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)


  这个方法很简单,因为数据处理实际上是由Adapter完成的。这一过程结束后,我们还要用一次Reflection API,不过这一次是设置表现控件的DataSource属性。   三、界面设计

  至此为止,分页控件的核心功能已经差不多实现,不过如果缺少适当的表现方式,分页控件不会很有用。

   为了有效地将表现方式与程序逻辑分离,最好的办法莫过于使用模板,或者说得更具体一点,使用Itemplate接口。实际上,微软清楚地了解模板的强大 功能,几乎每一个地方都用到了模板,甚至页面解析器本身也不例外。遗憾的是,模板并不象有些人认为的那样是一个简单的概念,需要花些时间才能真正掌握它的 精髓,好在这方面的资料比较多,所以这里就不再赘述了。返回来看分页控件,它有四个按钮:首页,前一页,后一页,末页,当然另外还有各个页面的编号。四个 导航按钮选自ImageButton类,而不是LinkButton类,从专业的Web设计角度来看,图形按钮显然要比单调的链接更有用一些。

一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)public ImageButtonFirstButton ... { get ... { return First;} }
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
public ImageButtonLastButton ... { get ... { return Last;} }
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
public ImageButtonPreviousButton ... { get ... { return Previous;} }
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
public ImageButtonNextButton ... { get ... { return Next;} }



   页面编号是动态构造的,这是因为它们依赖于数据源中记录数量的多少、每个页面显示的记录数量。页面编号将加入到一个Panel,Web设计者可以通过 Panel来指定要在哪里显示页面编号。有关创建页面编号的过程稍后再详细讨论,现在我们需要为分页控件提供一个模板,使得用户能够定制分页控件的外观。

一个相当独立的.通用分页控件c#源码三(downmoon收集)[TemplateContainer( typeof (LayoutContainer))]
一个相当独立的.通用分页控件c#源码三(downmoon收集)
public ITemplateLayout
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
get ... { return (_layout;}
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
set ... {_layout = value;}
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)
一个相当独立的.通用分页控件c#源码三(downmoon收集)
public class LayoutContainer:Control,INamingContainer
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集)
public LayoutContainer()
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... { this .ID = " Page " ;}
一个相当独立的.通用分页控件c#源码三(downmoon收集) }



  LayoutContainer类为模板提供了一个容器。一般而言,在模板容器中加入一个定制ID总是不会错的,它将避免处理事件和进行页面调用时出现的问题。下面的UML图描述了分页控件的表现机制。


一个相当独立的.通用分页控件c#源码三(downmoon收集)



创建模板的第一步是在aspx页面中定义布局:

一个相当独立的.通用分页控件c#源码三(downmoon收集)<LAYOUT>
一个相当独立的.通用分页控件c#源码三(downmoon收集) <asp:ImageButtonid
= " First " Runat = " server " imageUrl = " play2L_dis.gif "
一个相当独立的.通用分页控件c#源码三(downmoon收集) AlternateText
= " 首页 " >< / asp:ImageButton>
一个相当独立的.通用分页控件c#源码三(downmoon收集) <asp:ImageButtonid
= " Previous " Runat = " server " imageUrl = " play2L.gif "
一个相当独立的.通用分页控件c#源码三(downmoon收集) AlternateText
= " 上一页 " >< / asp:ImageButton>
一个相当独立的.通用分页控件c#源码三(downmoon收集) <asp:ImageButtonid
= " Next " Runat = " server " imageUrl = " play2.gif "
一个相当独立的.通用分页控件c#源码三(downmoon收集) AlternateText
= " 下一页 " >< / asp:ImageButton>
一个相当独立的.通用分页控件c#源码三(downmoon收集) <asp:ImageButtonid
= " Last " Runat = " server " imageUrl = " play2_dis.gif "
一个相当独立的.通用分页控件c#源码三(downmoon收集) AlternateText
= " 末页 " >< / asp:ImageButton>
一个相当独立的.通用分页控件c#源码三(downmoon收集) <asp:Panelid
= " Pager " Runat = " server " >< / asp:Panel>
一个相当独立的.通用分页控件c#源码三(downmoon收集)
/ LAYOUT>



  这个布局例子不包含任何格式元素,例如表格等,实际应用当然可以(而且应该)加入格式元素,请参见稍后的更多说明。

  Itemplate接口只提供了一个方法InstantiateIn,它解析模板并绑定容器。

一个相当独立的.通用分页控件c#源码三(downmoon收集)
一个相当独立的.通用分页控件c#源码三(downmoon收集)
private void InstantiateTemplate()
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集) _container
= new LayoutContainer();
一个相当独立的.通用分页控件c#源码三(downmoon收集) Layout.InstantiateIn(_container);
一个相当独立的.通用分页控件c#源码三(downmoon收集) First
= (ImageButton)_container.FindControl( " First " );
一个相当独立的.通用分页控件c#源码三(downmoon收集) Previous
= (ImageButton)_container.FindControl( " Previous " );
一个相当独立的.通用分页控件c#源码三(downmoon收集) Next
= (ImageButton)_container.FindControl( " Next " );
一个相当独立的.通用分页控件c#源码三(downmoon收集) Last
= (ImageButton)_container.FindControl( " Last " );
一个相当独立的.通用分页控件c#源码三(downmoon收集) Holder
= (Panel)_container.FindControl( " Pager " );
一个相当独立的.通用分页控件c#源码三(downmoon收集)
this .First.Click += new System.Web.UI.ImageClickEventHandler( this .First_Click);
一个相当独立的.通用分页控件c#源码三(downmoon收集)
this .Last.Click += new System.Web.UI.ImageClickEventHandler( this .Last_Click);
一个相当独立的.通用分页控件c#源码三(downmoon收集)
this .Next.Click += new System.Web.UI.ImageClickEventHandler( this .Next_Click);
一个相当独立的.通用分页控件c#源码三(downmoon收集)
this .Previous.Click += new System.Web.UI.ImageClickEventHandler( this .Previous_Click);
一个相当独立的.通用分页控件c#源码三(downmoon收集) }

一个相当独立的.通用分页控件c#源码三(downmoon收集)


   控件的InstatiateTemplate方法要做的第一件事情是实例化模板,即调用Layout.InstantiateIn (_container)。容器其实也是一种控件,用法也和其他控件相似。InstantiateTemplate方法利用这一特点寻找四个导航按钮,以 及用来容纳页面编号的Panel。导航按钮通过它们的ID找到,这是对分页控件的一点小小的限制:导航按钮必须有规定的ID,分别是First、 Previous、Next、Last,另外,Panel的ID必须是Pager,否则就会找不到。遗憾的是,就我们选定的表现机制而言,这似乎是较好的 处理方式了;但可以相信的是,只要提供适当的说明文档,这一小小限制不会带来什么问题。另外一种可选择使用的办法是:让每一个按钮从 ImageButton类继承,从而也就定义了一个新的类型;由于每一个按钮是一种不同的类型,在容器中可以实现一个递归搜索来寻找各种特定的按钮,从而 不必再用到按钮的ID属性。

  找到四个按钮之后,再把适当的事件句柄绑定到这些按钮。在这里必须做一个重要的决定,即何时调用 InstantiateTemplate。一般地,这类方法应当在CreateChildControls方法中调用,因为 CreateChildControls方法的主要用途就是这一类创建子控件的任务。由于分页控件永远不会修改其子控件,所以它不需要 CreateChildControls提供的功能来根据某些事件修改显示状态。显示子控件的速度总是越快越好,因此调用 InstantiateTemplate方法的比较理想的位置是在OnInit事件中。

一个相当独立的.通用分页控件c#源码三(downmoon收集)protected override void OnInit(EventArgse)
一个相当独立的.通用分页控件c#源码三(downmoon收集)一个相当独立的.通用分页控件c#源码三(downmoon收集)
... {
一个相当独立的.通用分页控件c#源码三(downmoon收集) _boundcontrol
= Parent.FindControl(BindToControl);
一个相当独立的.通用分页控件c#源码三(downmoon收集) BoundControl.DataBinding
+= new EventHandler(BoundControl_DataBound);
一个相当独立的.通用分页控件c#源码三(downmoon收集) InstantiateTemplate();
一个相当独立的.通用分页控件c#源码三(downmoon收集) Controls.Add(_container);
一个相当独立的.通用分页控件c#源码三(downmoon收集)
base .OnInit();
一个相当独立的.通用分页控件c#源码三(downmoon收集) }



  OnInit方法除了调用InstantiateTemplate方法,它的另一个重要任务是将容器加入分页控件。如果不将容器加入到分页器的控件集合,由于Render方法永远不会被调用,所以模板就不可能显示出来。

  模板还可以用编程的方式通过实现Itemplate接口定义,这一特性除了可作为提高灵活性的措施之外,还可以提供一个默认的模板,以便在用户没有通过aspx页面提供模板时使用。