本篇继续上篇的讨论,可能大家已经在使用asp.net2.0了,DataSource属性不再使用,而是跟数据源控件搭配使用.现在讨论的绑定技术都是基于1.1版本,先熟悉一下,本质上是一样的,这样一步步的学习.对以后绝对有帮助.因为当你使用数据源控件,只需要设置一个DataSourceID,方便的同时你是否知道数据源控件帮你做了什么事情,如果你想觉的够用了,可以不用了解,但我相信你一定会有需求。上篇最后说过了,讨论还刚刚开始,我们大致把核心的方法都写出来了.下面我们继续。

  一.控件对比

  我们可以使用上篇制作的TemplatedList控件跟内置控件做一下对比异同。在2.0未到来的时候,我们只有Repeater,DataList,DataGrid,现在我们也根据这三个控件进行讨论,下面把TemplatedList与DataList进行对比

  (1)布局样式没DataList多...

  (2)模板没DataList多...

  (3)TemplatedList没ItemCollection

  (4)TemplatedList没有预定义Command事件(如EditCommand,UpdateCommand等)

  或者还有更多的,上面的都是次要的,布局上面我们可以改善,我们也可以添加ItemCollection,也可以预定义Command事件,但发现TemplatedList跟内置的绑定控件有几个跟数据操作严重的不同点

  (1)DataSource属性类型不同  IEnumerable和Object

  为什么要将其类型设置为Object呢?

  IEnumerable支持Array,ArrayList等返回类型,但却不支持DataSet类型,这是一个很严重的问题,设置其类型为Object,可以让控件支持更广泛的数据源(当然也要根据需求)这个是本次讨论的重点

  (2)DataMember

  其用于指定数据源的特定表,由于DataSet的介入,其可能含有多个表,所以也就有了这个属性,否则的话就不需要他

  (3)DataKeyField键字段

  由于预定义Command事件的介入,实现对数据的操作,DataKeyField用于帮助数据特定记录的操作

  二.确定目标

  根据上面的对比,我们已经知道接下来要做什么了,要让控件DataSouce属性支持更多的数据源(只要还是DataSet)

  本次的demo我们将要模仿Repeater来制作,为什么不用TemplatedList?因为这样我们可以对更多控件的实现更加的熟悉,这样在使用内置控件的时候,你将明白的更透彻.此处的demo来自Building ASP.NET Server Controls书中的例子

  Repeater与TemplatedList的异同

  不同点

  大家都知道Repeater可以灵活的进行布局,所以去掉了模板样式属性,我们为其添加了多个模板属性,Repeater控件没有预定义Command事件,所以不需要DataKeyField属性.还为Repeater定义了TemplatedListmy没有的ItemCollection集合,当然也可以为TemplatedList添加这个集合最大的不同。Repeater支持DataSet,TemplatedList不支持。

  相同点

  都是数据绑定控件,所以里面很多的实现方法几乎相同,如果你看过TemplatedList的实现,再看Repeater的代码,基本没有难度,Repeater的实现比TemplatedList还要简单。

  好了,下面我们开始吧.

  三.实现

  1.为数据控件做好准备

  几乎跟上篇一样,所以不再介绍

  2.编写Repeater

  (1)定义成员属性和事件

private object dataSource;
/// <summary>
/// 绑定的列表的数据源
/// </summary>
[Category("Data"), Description("绑定的列表的数据源"),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
DefaultValue(null), Bindable(true)]
public object DataSource
{
get
{
return dataSource;
}
set
{
if ((value is IEnumerable) || (value is IListSource) || (value == null))
dataSource = value;
else
throw new Exception("错误的数据源类型");
}
}

/// <summary>
/// 当数据绑定到列表数据源时要提取的数据成员
/// </summary>
[Category("Data"), Description("当数据绑定到列表数据源时要提取的数据成员")]
public virtual string DataMember
{
get
{
object member = ViewState["DataMember"];
if (member == null)
return string.Empty;
else
return (string)member;
}
set
{
ViewState["DataMember"] = value;
}
}

主要的变化在于DataSource,类型更改为object其对传入的数据源进行判断,另外还加入了DataMember属性

  (2)关键实现

  1.因为Repeater模板不具有样式属性,所以去掉了PrepareControlHierarchy方法。

  2.由于不涉及到复杂的样式属性,所以不必重载视图状态管理的三个方法。

  这两点就可以让控件减少很多代码的编写

  3.CreateControlHierarchy方法和CreateItem方法

  Repeater模板的实现方法和TemplatedList稍有不同,但变化不大,应该容易理解.看下面代码

/// <summary>
/// 创建控件各种项
/// </summary>
/// <param name="itemIndex"></param>
/// <param name="itemType"></param>
/// <param name="dataBind"></param>
/// <param name="dataItem"></param>
/// <returns></returns>
private RepeaterItem CreateItem(int itemIndex, ListItemType itemType, bool dataBind, object dataItem)
{
ITemplate selectedTemplate;
//根据不同类型创建不同项
switch (itemType)
{
case ListItemType.Header:
selectedTemplate = headerTemplate;
break;
case ListItemType.Item:
selectedTemplate = itemTemplate;
break;
case ListItemType.AlternatingItem:
selectedTemplate = alternatingItemTemplate;
break;
case ListItemType.Separator:
selectedTemplate = separatorTemplate;
break;
case ListItemType.Footer:
selectedTemplate = footerTemplate;
break;
default:
selectedTemplate = null;
break;
}

if ((itemType == ListItemType.AlternatingItem) &&
(alternatingItemTemplate == null))
{
selectedTemplate = itemTemplate;
itemType = ListItemType.Item;
}

RepeaterItem item = new RepeaterItem(itemIndex, itemType, dataItem);

if (selectedTemplate != null)
{
selectedTemplate.InstantiateIn(item);
}

OnItemCreated(new RepeaterItemEventArgs(item));

Controls.Add(item);

if (dataBind)
{
item.DataBind();
OnItemDataBound(new RepeaterItemEventArgs(item));
}
return item;
}

private ArrayList items = null;
private void CreateControlHierarchy(bool useDataSource)
{
items = new ArrayList();
IEnumerable ds = null;

if (HeaderTemplate != null)
{
RepeaterItem header = CreateItem(-1, ListItemType.Header, false, null);
}

int count = -1;
if (useDataSource)
{
//解析DataSource
ds = (IEnumerable)DataSourceHelper.ResolveDataSource(DataSource,
DataMember);
}
else
{
count = (int)ViewState["ItemCount"];
if (count != -1)
{
ds = new DummyDataSource(count);
}
}

if (ds != null)
{
int index = 0;
count = 0;
RepeaterItem item;
ListItemType itemType = ListItemType.Item;

foreach (object dataItem in (IEnumerable)ds)
{
if (index != 0)
{
RepeaterItem separator = CreateItem(-1, ListItemType.Separator, false, null);
}

item = CreateItem(index, itemType, useDataSource, dataItem);
items.Add(item);
index++;
count++;

if (itemType == ListItemType.Item)
itemType = ListItemType.AlternatingItem;
else
itemType = ListItemType.Item;
}
}

if (FooterTemplate != null)
{
RepeaterItem footer = CreateItem(-1, ListItemType.Footer, false, null);
}

if (useDataSource)
{
ViewState["ItemCount"] = ((ds != null) ? count : -1);
}
}

其中最大的变化在于这里,因为还需要支持DataSet,DataSourceHelper类负责解析传入的数据源DataSouce进行解析

            if (useDataSource)
            {
                //解析DataSource
                ds = (IEnumerable)DataSourceHelper.ResolveDataSource(DataSource,
                   DataMember);
            }

  下面我们来重点看DataSourceHelper类,DataSourceHelper类可谓是这一篇的重头戏,关键就在于这里的理解.这里搞明白了,才算是明白.一起来看吧

// <summary>
/// 一个解析DataSource的辅助类
/// </summary>
public class DataSourceHelper
{
public static object ResolveDataSource(object dataSource, string dataMember)
{
如果数据源为空,则返回空值

如果数据源不为空,且为IEnumerable类型,则返回IEnumerable

如果数据源不为空,且为IListSource类型,则返回IListSource
return null;

}
}

  这个辅助类判断太多,刚看会看晕掉的,所以在if判断这里把代码折叠起来,有助于理解。这里有几个类可能没见过,我们把关键用到的类一一列出来,希望大家查查MSDN

  1.IListSource  向对象提供返回可以绑定到数据源列表的功能

  2.ITypedList   提供发现可绑定列表架构的功能,其中可用于绑定的属性不同于要绑定到的对象的公共属性

  3.PropertyDescriptor  提供类上的属性的抽象化

  4.PropertyDescriptorCollection 表示 PropertyDescriptor 对象的集合

  下面开始

  (1).首先如果传入的数据源类型是IEnumerable的话,很好,可以直接返回

            if (dataSource is IEnumerable)
            {
                return (IEnumerable)dataSource;
            }

(2).转化实现IListSource接口的类 

  虽然传入的类型非IEnumerable,如DataSet类实现了IListSource接口,其目的就是使用此接口的GetList方法返回一个IList(IList继承IEnumerable,可以进行数据绑定),大家可以参考MSDN的原话

                IList list = null;
                IListSource listSource = (IListSource)dataSource;
                list = listSource.GetList();

假设传入的是DataSet,list将会得到System.Data.DataViewManager集合 ,DataViewManager是什么呢?为默认DataTable默认的DataViewSettingCollection

  DataViewSettingCollection是什么呢?表示DataTable的DataViewSetting的集合

  DataViewSetting是什么呢?表示从 DataViewManager 创建的 DataView 的 的默认设置

  上面的我们不熟,DataView大家应该熟悉,其可以对数据进行排序,过滤等。DataViewManager为一个默认的DataView设置集合,不知这样是否可以理解的好些。我们的目的则是将其转化到IEnumerable类型,继续DataViewManager实现了ITypedList接口。我们需要将DataViewManager(即list)转化到ITypedList ,为什么?ITypedList的GetItemProperties方法将帮助你获取DataView数据绑定的数据对象,而非DataView本身属性。

  ITypedList的GetItemProperties方法绑定数据的每项属性的PropertyDescriptorCollection集合,PropertyDescriptorCollection表示PropertyDescriptor集合,PropertyDescriptor这个类很好玩,等同于属性的说明书,即用了.net的反射技术,大家可以尝试一下,其实以前也用过这个类.下面来看代码片段

//提供发现可绑定列表架构的功能,其中可用于绑定的属性不同于要绑定到的对象的公共属性
  ITypedList typedList = (ITypedList)list;
   //返回表示用于绑定数据的每项上属性集合
    PropertyDescriptor[] pd = new PropertyDescriptor[0];
    PropertyDescriptorCollection propDescCol =
    typedList.GetItemProperties(pd);  //was (null)
    //如果属性说明符数目为0
    if (propDescCol.Count == 0)
    throw new Exception("ListSource without DataMembers");

  GetItemProperties方法传入了一个PropertyDescriptor的数组,大家可能注意到了传入的数组为一个空数组,你还可以传入一个空引用

PropertyDescriptorCollection propDescCol =
                       typedList.GetItemProperties(null);  //was (null)

  如果你为DataTable创建了DataView,将调用空引用返回DataSet中的一个DataTable,其将返回一个表集合列的属性描述符,继续看下去,该到DataMember出场的时候了,DataMember可以选择数据集中的特定表,如何不设置DataMember,将获取默认表,看下面代码片段

#region 判断dataMember字符数给propDesc赋值
//获取属性描述符
//若不指定dataMember属性则获取默认数据成员
if ((dataMember == null) || (dataMember.Length < 1))
{
propDesc = propDescCol[0];
}
else
//尝试在属性集合中寻找数据成员
propDesc = propDescCol.Find(dataMember, true);

#endregion

if (propDesc == null)
throw new Exception("ListSource missing DataMember");

  这样我们就得到了一个DataTablePropertyDescriptor属性描述符,继续

                    object listitem = list[0];

                    //获取组件属性当前值
                    object member = propDesc.GetValue(listitem);

                    if ((member == null) || !(member is IEnumerable))
                        throw new Exception("ListSource missing DataMember");

                    return (IEnumerable)member;

  此处实现原理:

  DataViewManager会在其DataSet中的DataTableCollection中搜索datamember的值进行匹配,看下图,做这么多事情,我们一直在转换

  注:GetValue用法

        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(Button1);
        PropertyDescriptor pd = properties.Find("Text", false);
        Button b=new Button();
        b.Text = "cc";
        object c=pd.GetValue(b);
        Response.Write(c);
        //return cc

  用GetValue方法获取listitem属性值,此属性跟datamember匹配,最后member得到的是一个DataView,DataView实现了IEnumerable,现在终于可以转换了。到此为止就结束了,现在你可以成功的传入DataSet了。

上一篇:asp.net控件开发基础(17)

下一篇:asp.net控件开发基础(19)

转载于:https://www.cnblogs.com/waw/archive/2011/09/01/2162811.html

一起谈.NET技术,asp.net控件开发基础(18)相关推荐

  1. 一起谈.NET技术,asp.net控件开发基础(17)

    本篇将开始介绍如自定义数据绑定控件,这里感谢很多人的支持,有你们的支持很高兴.这里首先需要大家熟悉asp.net模板控件的使用,还有自定义模板控件.因为数据绑定控件多是基于模板控件的. 一.回顾 如果 ...

  2. asp.net控件开发基础系列

    本系列文章示例源码下载.各位如遇问题,请多查msdn,多利用网络.本人可能没时间一一回复,谢谢你们的支持,希望看到此文的人都能学好控件开发 http://www.cnblogs.com/Clingin ...

  3. 一起谈.NET技术,asp.net控件开发基础(13)

    1.减轻服务器压力,增加用户体验 服务器功能是强大的,客户端脚本一点也不弱,现在的ajax技术和Atlas技术就是最好的证明,我们总是期待UI有一个好的效果,flash动画给我们带来了很酷的效果,我们 ...

  4. 一起谈.NET技术,asp.net控件开发基础(20)

    上面我们讨论了数据绑定控件的做法,但都未涉及到asp.net2.0中数据源控件的用法,让用惯了数据源控件的人可能感觉不适应.这次我们就开始讨论在asp.net2.0中,我们该如何重新定义数据绑定控件. ...

  5. 一起谈.NET技术,asp.net控件开发基础(9)

    写第五篇的时候,我一步步的加上元数据(特性),使得设计时效果更加好,如对复杂属性应用以下特性,使属性浏览器支持扩展/折叠效果,使你更加容易编辑子属性,但接着我又遇到了问题,所以必须去解决 1.认识默认 ...

  6. asp.net控件开发基础(2)

    上一篇:http://www.cnblogs.com/Clingingboy/archive/2006/07/30/463471.html 或许大家还对为何要重写Render方法存有疑惑,希望大家看看 ...

  7. asp.net控件开发基础十四

    http://www.cnblogs.com/Clingingboy/archive/2006/09/29/514722.html      上一篇讨论了为服务器控件添加客户端功能,这一篇我们所要讲的 ...

  8. asp.net控件开发基础(21)

    示例代码 上篇介绍了在asp.net2.0版本下面如何简单的定义数据绑定控件.虽然DataBoundControl为我们提供了便利,我们以后可以从此类开始编写数据绑定控件.但是在2.0版本未到来之前, ...

  9. asp.net控件开发基础(19)

    上两篇讨论了基本数据绑定控件的实现步骤,基本上我们按着步骤来就可以做出简单的数据绑定控件了.过年前在看DataGrid的实现,本来想写这个的,但2.0出了GridView了,再说表格控件实现比较复杂, ...

最新文章

  1. 唉,面试官这 5 道题,难为我这 3 年经验了
  2. python打开后的界面-Python - tkinter:打开和关闭对话框窗口
  3. [转]div里table居中的问题 Div与body顶部间隙
  4. spring boot实战(第四篇)分散配置
  5. emberjs重写补充类之reopen方法和reopenClass方法
  6. C语言的指针初始化特别注意一点
  7. ps中如何同图层获取css代码
  8. 【差分隐私的指数机制该怎么理解?】差分隐私系统学习记录(三)
  9. 超棒的30款JS类库和工具
  10. 升级ssl后ssh登录失效_centos7升级openssl、openssh常见问题及解决方法
  11. 软件体系结构六大质量属性-浅析淘宝网
  12. iOS 蓝牙扫描设备注意 2021-10-12
  13. 墨墨背单词mysql_GitHub - FunStuff/WeChat-applets: 微信小程序小鸡单词
  14. 计算机Excel设置透视图,excel共享表格数据-EXCEL在共享模式中,如何让数据透视表能够自动刷新?...
  15. QQ VS 360 大战开始
  16. 心情纸条/心动盲盒/交友盲盒
  17. 计算机与信息安全的基本知识,信息安全的基本常识
  18. python 图书管理_Python-图书管理系统
  19. Android编程权威指南笔记3:Android Fragment讲解与Android Studio中的依赖关系,如何添加依赖关系
  20. fitbit同步不了怎么解决_Fitbit用户投诉,升级Android 9 Pie后无法同步

热门文章

  1. 如何学习linux编程
  2. Linux内存管理大图(第三稿)
  3. 汇编语言使用C库函数和Linux动态链接
  4. 一种精确从文本中提取URL的思路及实现
  5. 对象检测工具包mmdetection简介、安装及测试代码
  6. 提高C++性能的编程技术笔记:内联+测试代码
  7. C++中try/catch/throw的使用
  8. 【FFmpeg】函数详解(二)
  9. 【OpenCV】正确创建用于保存YUV420P格式的cv::Mat
  10. blf文件用什么软件打开_如何用皕杰流程创建一个blf演示流程文件?