DataTable 深入解析数据源绑定原理之高级篇

  前言

  在上篇写了篇 实战系列之天气预报实时采集 ,有个别同志认为没技术含量,也许正如所说。

只是人各有看法,当我写出一篇文章时,我只是希望:

1:如果你还不懂,请看写法,了解想法。

2:如果你已懂,略过写法,请看想法。

  其实纵观我一直写来的200多篇文章,基本都可以看出那么点痕迹:

一:没有水文。

二:没有华丽理论型的文章。

三:实战型文章很多。

四:文章尽量面向新手的表述,尽量了。

  一、Winform下的DataGridView不支持使用DataReader绑定

  1:问题产生

在 CYQ.Data 框架 进行到V1.5版本要支持Winform时,曾遇到一个问题,就是无法绑定DataGridView。

  2:思考分析试验

MDataTable走的是DataReader方式实现的绑定,除非DataReader无法绑定DataGridView,不然就是自己实现有问题。

因此,做个试验:使用SqlDataReader直接绑定Winform下的DataGridView,发现失败了。

于是
大量搜索,发现DataReader实在无法直接绑定DataGridView,通过数据源控件中转绑定的就算了。

  3:得出结论

DataReader方式都无法绑定Winform下的DataGridView,我这继承之DataReader的实现方式也就更无从实现绑定了。

只好另寻方法-》DataGridView支持DataTable,于是要从DataTable入手了。

  二、DataTable很强大,支持Web又支持Winform

  1:分析绑定原理

在以前的MDataTable实现绑定原理篇中,我们研究出要实现绑定,有两种方式:

一种是实现IEnumerable接口,即当初走的DataReader方式实现的绑定。

另一种是实现IListSource接口,即走DataTable方式实现的绑定。

为啥当初不实现DataTable方式的绑定,不就完了,两种都支持~~-_-..现在又得回去折腾IListSource接口的实现。

  2:深入DataTable绑定原理

  我们通过Reflector反编绎看下DataTable继承实现的接口:

public class DataTable : MarshalByValueComponent, IListSource, ISupportInitializeNotification, ISupportInitialize, ISerializable, IXmlSerializable

  几乎都是我们平常没用到的接口,不理先,我们关注IListSource怎么实现绑定的。如果自己看一下IListSource要实现的接口有几个方法:

public interface IListSource

{

    // Methods

    IList GetList();

    // Properties

    bool ContainsListCollection { get; }

}

  就两个,太容易了,接着我们要在DataTable 6000多行的代码中找到IListSource的实现,查找是最好的方法:

//DataTable的实现

bool IListSource.ContainsListCollection

{

    get {  return false; }}

IList IListSource.GetList()

{

    return this.DefaultView;

}

  GetList接口没事就返回了个默认视图,又要切进去看视图了。

public DataView DefaultView

{

    get

    {

        DataView defaultView = this.defaultView;

        if (defaultView == null)

        {

            if (this.dataSet != null)

            {

                defaultView = this.dataSet.DefaultViewManager.CreateDataView(this);

            }

            else

            {

                defaultView = new DataView(this, true);

                defaultView.SetIndex2("", DataViewRowState.CurrentRows, null, true);

            }

            defaultView = Interlocked.CompareExchange<DataView>(ref this.defaultView, defaultView, null);

            if (defaultView == null)

            {

                defaultView = this.defaultView;

            }

        }

        return defaultView;

    }

}

  切进去就一大堆,实在没心情看下去,省略中间看个头与尾,只知道返回了个DataView。

public class DataView : MarshalByValueComponent, IBindingListView, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitializeNotification, ISupportInitialize

  忽悠:

又是神马般的一堆接口,内部代码太多,实在没心情看;

我只想知道IListSource怎么实现绑定,至于其它有一堆没一堆的我根本不关心,我只要我想要的。

扫了一眼接口,发现是继承了IList,这和IListSource要求的返回值IList是一致的。

  神马啊神马,没点头绪,完全找不到绑定的重点,难道说,随便找个IList返回的类就行了?于是让MDataTable实现IListSource接口,试试看:

public class MDataTable : IDataReader, IEnumerable,System.ComponentModel.IListSource

  实现接口:

public IList GetList()

{

    return Rows;

}

  接着忽悠:

好说我的Rows也是继承自List<xxx>的,试着绑定~~结果很飘逸,出来完全不是我想象~~。

继承折腾DataView,传说DataView也能直接绑定控件的,yo~~有一丝想法。。

  于是看一下其实现IList接口的源码,发现一堆都在操作DataRowView

public class DataRowView : ICustomTypeDescriptor, IEditableObject, IDataErrorInfo, INotifyPropertyChanged

  没法忽悠了:

你个XX,从DataTable-》DataView-》DataRowView,再转我头就晕了~~。

又是一堆很陌生的接口,于是到这里,我几乎停止了脚步,因为我分析不下去了~~。

  上WC仔细从头想过:

  对于IList<实体>绑定,所有的属性都会被认为是列名,其值为行的值。而对于DataTable,里面又是怎么认识出列名和分析出值的呢?

1:从DataTable中,我们看到一丝列名提取的相关方法,只是返回->DataRow。

2:从DataRow中也看不到提取列名的方法,其关键性的IList接口的相关实现引出了->DataRowView。

3:DataRowView?是神秘的所在?一堆继承的接口也是很陌生。

  回头继续搜索:

  转换思路继续大量搜索:换了很多关键字,搜中文又搜E文。结果尽是一堆自定义控件开发的东东,结果印象中在某一篇的googleE文的“网页快照”中发现一段E文,原文不知是哪了,上次都记得只能打开快照,现在估计能快照都没了,按想象翻译出来的中文大致为:

DataTable能实现其绑定,是因为其实现了ICustomTypeDescriptor,从而获得其属性。

  偶滴神啊~能从千军万马的E文中,扫到几个关键字不容易啊!!!

如果回过头看上面的DataRowView,就会发现,正好,它实现了接口ICustomTypeDescriptor,

只是遥想当年,我并不像现在写文这么冷静,我当初早把Reflector关掉了,哪还记得DataRowView实现了ICustomTypeDescriptor,

再说ICustomTypeDescriptor对我又是那么的陌生,是那么的陌生,...很陌生。。。

  秘密已经出来了:

ICustomTypeDescriptor接口,一个移动控件开发人员经常打交道的接口,对于我们却极为陌生的接口。

是它,就是它,就是它实现如何识别哪些是列名,哪些是列值。

  3:浅入ICustomTypeDescriptor

当初我通过大量的搜索,试图找到相关的应用示例,因为那时我不知道DataRowView,要是知道,我就
不用那么辛苦去搜文章了。

如果你搜索此接口,你会发现一堆的文章都是说移动控件开发,我就是从移动控件开发中很辛苦的挖了点示例实现了。

  不过此文就不走弯路了,直接分析DataRowView,对于 ICustomTypeDescriptor接口,有很多方法:

public interface ICustomTypeDescriptor

{

    // Methods

    AttributeCollection GetAttributes();

    string GetClassName();

    string GetComponentName();

    TypeConverter GetConverter();

    EventDescriptor GetDefaultEvent();

    PropertyDescriptor GetDefaultProperty();

    object GetEditor(Type editorBaseType);

    EventDescriptorCollection GetEvents();

    EventDescriptorCollection GetEvents(Attribute[] attributes);

    PropertyDescriptorCollection GetProperties();

    PropertyDescriptorCollection GetProperties(Attribute[] attributes);

    object GetPropertyOwner(PropertyDescriptor pd);

}

  不过基本是摆设,只因用不到,除了一个接口方法:GetProperties(Attribute[] attributes)

  于是我们分析DataRowView对此接口的实现:

PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes)

{

    if (this.dataView.Table == null)

    {

        return zeroPropertyDescriptorCollection;

    }

    return this.dataView.Table.GetPropertyDescriptorCollection(attributes);

}

  继续深入:

internal PropertyDescriptorCollection GetPropertyDescriptorCollection(Attribute[] attributes)

{

    if (this.propertyDescriptorCollectionCache == null)

    {

        int count = this.Columns.Count;

        int num4 = this.ChildRelations.Count;

        PropertyDescriptor[] properties = new PropertyDescriptor[count + num4];

        for (int i = 0; i < count; i++)

        {

            properties[i] = new DataColumnPropertyDescriptor(this.Columns[i]);

        }

        for (int j = 0; j < num4; j++)

        {

            properties[count + j] = new DataRelationPropertyDescriptor(this.ChildRelations[j]);

        }

        this.propertyDescriptorCollectionCache = new PropertyDescriptorCollection(properties);

    }

    return this.propertyDescriptorCollectionCache;

}

  关键定位,只是返回一组:DataColumnPropertyDescriptor 。

  那DataColumnPropertyDescriptor是什么?继续深入:

internal DataColumnPropertyDescriptor(DataColumn dataColumn) : base(dataColumn.ColumnName, null)

{

    this.column = dataColumn;

}

  两行代码,那个base是啥?是PropertyDescriptor ,实现很简单,把列名传过去就行了,至此,就结束了。不知道有多少会看到这里,估计本文大伙也就是扫下来,除非某天要应用到,不然只是忽悠下眼球了。

  总结下具体实现ICustomTypeDescriptor接口方法:

1:继承实现接口方法。

2:重点实现GetProperties(Attribute[] attributes)方法。

3:需要自定义属性描述类,而这自定义的属性描述类需要继承自抽象基类PropertyDescriptor。

4:GetProperties返回的是自定义属性描述类的集合。

  三、绑定原理分析完,MDataTable模仿出击

  1:MDataTable继承IListSource接口实现

#region IListSource 成员

        public bool ContainsListCollection

        {

            get

            {

                return true;

            }

        }

        public IList GetList()

        {

            return Rows;

        }

        #endregion

  2:MDataRow继承ICustomTypeDescriptor接口实现

  A:先实现自定义属性描述类

自定义属性描述类MDataPropertyinternal class MDataProperty : System.ComponentModel.PropertyDescriptor

    {

        private MDataCell cell

时间: 2024-11-08 20:12:08

DataTable 深入解析数据源绑定原理之高级篇的相关文章

一起谈.NET技术,DataTable 深入解析数据源绑定原理之高级篇

前言 在上篇写了篇 实战系列之天气预报实时采集 ,有个别同志认为没技术含量,也许正如所说. 只是人各有看法,当我写出一篇文章时,我只是希望:1:如果你还不懂,请看写法,了解想法.2:如果你已懂,略过写法,请看想法. 其实纵观我一直写来的200多篇文章,基本都可以看出那么点痕迹: 一:没有水文.二:没有华丽理论型的文章.三:实战型文章很多.四:文章尽量面向新手的表述,尽量了. 一.Winform下的DataGridView不支持使用DataReader绑定 1:问题产生 在 CYQ.Data 框架

.NET各大平台数据列表控件绑定原理及比较(WebForm、Winform、WPF)

说说WebForm: 数据列表控件: WebForm 下的列表绑定控件基本就是GridView.DataList.Repeater:当然还有其它DropDownList.ListBox等.   它们的共同的设置数据源方法: XXX.DataSource=数据源.   那么这个数据源的格式,究竟有啥要求?最简单的方式是随便给弄个,然后等它抛异常:     从上面的错误可以看的出来,基本上支持三种数据源绑定方式:IListSource,IEnumerable,IDataSource.   说说Win

[WebKit] JavaScriptCore解析--高级篇(一) SSA (static single assignment)

在编译器优化领域,数据结构的选择会直接影响程序优化的有效性.SSA是一种编译器使用的中间语言(intermediate language), 作为编译优化的基础(也是DFG JIT的基础),它和Control Dependence Graph一起被用来表示程序的数据流和控制流. 大家都知道编译器是这样工作的:解析.优化,最后生成代码.中间会使用到一个中间语言的进行过度,好的中间语言一定要      1. 简单,这样优化工作就可以变得简单.      2. 很好的表达能力,这样就可以很容易从源代码

数据绑定技术—将DataReader做为数据源绑定到DataGrid控件

SqlDataReader dr; void Page_Load(object sender, System.EventArgs e) { // 数据连接字符串及 SQL 语句 string ConnStr = System.Configuration.ConfigurationSettings.AppSettings["ConnectionSqlServer"]; string query = "SELECT * FROM Categories"; // 创建并打

listview-Json解析后绑定到ListView

问题描述 Json解析后绑定到ListView 最近在做项目,碰到的问题,需要将服务器返回的结果进行json解析然后将其绑定到ListView上,我的json解析代码如下: public ArrayList<HashMap<String, String>> analyzeJson(String responseBody, String arrayName, String objName) throws Exception { JSONObject json = new JSONOb

数据源绑定的datagridview和combobox如何实时更新数据

问题描述 数据源绑定的datagridview和combobox如何实时更新数据 经过绑定,数据源更新后,空间里的数据并不能及时更新,要重新打开窗口才可!

[WebKit] JavaScriptCore解析--高级篇(二) 类型推导(Type Inference)

类型推导是DFG JIT最重要的一个基础,WebKit官网对此做了一点解释,翻译如下做为学习参考. Type inference通过profiling values来做到的,先是预测对哪些类型操作进行分析,再添加类型检查,最后基于类型检查的结果建立类型统计数据. 用下面的例子来说明这个过程: o.x * o.x + o.y * o.y 其中o是一个对象,x和y是它的属性,它们不是访问器(accessor),只是一般的属性.我们也可以说这两个属性值会返回double类型数值,但也有时会返回整型数据

[WebKit] JavaScriptCore解析--高级篇(三) Register Allocation &amp;amp; Trampoline

Register Allocation 对于一个JIT而言,寄存器分配对系统的消耗通常是一个瓶径.之前有Graph Coloring Allocators, Chaitin style等分配方式,现在要介绍的是DFG JIT使用的Linear Scan算法.其基本工作方式是将占用寄存器的变量根据生命周期长短排列出来,在使用时查看可以回收哪些寄存器加以利用. 先看一些定义: •Live interval:是某个变量可以存活的一个指令序列,也可以称为了连续性.这个也依赖于算法使用的是深度优先还是广度

ASP.NET实现TreeView的XML数据源绑定实例代码_实用技巧

TreeView控件可以使用XML文档作为数据源,根据XML文档的层次结构显示节点.而XML文档的访问由XmlDataSource控件来完成,从XmlDataSource控件的DataFile属性中指定XML文档路径,然后在TreeView控件中设置与XML文档中的节点的对应关系.本示例将演示如何把TreeView控件绑定到XML数据源. 技术要点把TreeView控件绑定到XML数据源的技术要点如下. 使用XmlDataSource控件提供对XML文档的访问. 在TreeView控件的Data