手把手教你写Ajax驱动的DataGrid控件(二)
手把手教你写Ajax驱动的DataGrid控件(二)
二. 指导思想
做任何事情,都需要一个思想作为指导,我们的控件当然也不例外。
1. 控件的名字(我们姑且叫他AjaxGrid吧,后文将一直用此名称)
2. 面向控件的使用人员(即开发人员),我们要求代码尽可能得精简,API(包括JavaScript)丰富
3. 面向最终用户,我们要求响应迅速、界面精美并且符合使用习惯(本地化)
居于以上几点,我们进入主题,开始我们的编码之旅。
三. 编写控件代码
Asp.net的用户控件非常令人兴奋,它比任何OO宣传的代码重用都要来的实际,因为任何一个人即便OO了,他还是有可能在下一个项目中重写这些代码,而控件,不管是初学还是老手,重用是必然的。你不需要掌握太多的服务器控件开发方法,因为我们的控件要实现需求,并不会使用到控件的一些更高深的东东,如模版控件、回调、数据绑定和状态管理等,我们需要的只是重写Render方法。
为什么要重写Render方法,因为我们要在页面输出自己的Html,而我们控件的本来面貌就是一个Html table。可是还有一个问题,我们需要翻页和过滤数据,这就要求我们的table必须重绘,毫无疑问,重绘的数据当然来自服务器。刷新页面是常用的办法,但是别忘了,我们做的可是Ajax表格哦^_^。也许你会想到XmlRequest,正是,我们其实都很容易想到它,不用刷新的问题解决了。可还有一个问题,服务器要是没有保留表格的数据源怎么办?我们在以后再次请求它生成符合要求的表格时它却告诉你它把数据源给丢了,那样可行不通。其实问题也很简单,我们就让它保留数据源供以后翻页和过滤数据使用,直到我们确定不再使用这个数据源(AjaxGrid销毁),再将其“丢掉”。
下面将逐步实现上面的几点。
1. 为控件指定数据源,并保存它直到不再需要为止
我们选择采用System.Data.DataTable作为我们的最终数据源,因为它便于排序、翻页、和过滤数据。但是,控件的使用者(开发人员)可不希望为了使用我们的控件每次都去生成一个DataTable,那怎么办?既然别人不愿意干,那就我们自己动手了。我们发现,可以绑定到服务器控件的数据源,都会实现IListSource 或IEnumerable 接口,也就是说,我们只要检查开发人员为控件指定的数据源是否实现了上述两个接口中的一个,(如果没有呢?这个问题还要问吗,给他点异常看看他下次保证就不敢了),再将它们转化为DataTable。代码如下:
using System;
using System.Data;
using System.Collections;
using System.ComponentModel;
namespace Wfyfngu.Web.UI
{
/**////
/// DataSourceHelper 的摘要说明。
///
internal class DataSourceHelper
{
private static IEnumerable ResolveDataSource(object dataSource, string dataMember)
{
// 如果是 IListSource
if(dataSource is IListSource)
{
IListSource listSource = (IListSource)dataSource;
IList list = listSource.GetList();
//
if(listSource.ContainsListCollection)
{
ITypedList typedList = (ITypedList)list;
PropertyDescriptorCollection collection = typedList.GetItemProperties(new PropertyDescriptor[0]);
if(collection.Count == 0)
throw new Exception("ListSource without DataMembers");
PropertyDescriptor descriptor = null;
if (dataMember == null || dataMember == string.Empty)
{
descriptor = collection[0];
}
else
{
descriptor = collection.Find(dataMember, true);
}
if(descriptor == null)
throw new Exception("ListSource missing DataMember");
object listItem = list[0];
object member = descriptor.GetValue(listItem);
if (member == null || !(member is IEnumerable))
throw new Exception("ListSource missing DataMember");
return (IEnumerable)member;
}
else
{
return (IEnumerable)list;
}
}
if(dataSource is IEnumerable)
{
return (IEnumerable)dataSource;
}
throw new Exception("None IListSource or IEnumerable.");
}
/**////
/// 将实现了IListSource 和 IEnumerable的数据源转换为 DataTable
///
///
///
internal static DataTable ConventToDataTable(object dataSource)
{
if(dataSource == null)
return new DataTable();
IEnumerable ie = ResolveDataSource(dataSource, null);
DataTable table = new DataTable();
int colIndex = 0;
ArrayList rows = new ArrayList();
foreach(object item in ie)
{
if(item is DataRowView)
{
table = ((DataRowView)item).DataView.Table;
for(int i=0; i
table.Columns[i].ColumnName = "f"+i.ToString();
return table;
}
//
table.Columns.Add("f"+(colIndex++).ToString());
rows.Add(item);
}
object[] o = new object[rows.Count];
for(int i=0; i
o[i] = rows[i];
table.Rows.Add(o);
return table;
}
}
}