1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 一起谈.NET技术 DataTable 深入解析数据源绑定原理之高级篇

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

时间:2020-05-13 13:54:45

相关推荐

一起谈.NET技术 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继承实现的接口:

publicclassDataTable:MarshalByValueComponent,IListSource,ISupportInitializeNotification,ISupportInitialize,ISerializable,IXmlSerializable

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

publicinterfaceIListSource

{

//Methods

IListGetList();

//Properties

boolContainsListCollection{get;}

}

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

//DataTable的实现

boolIListSource.ContainsListCollection

{

get{returnfalse;} }

IListIListSource.GetList()

{

returnthis.DefaultView;

}

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

publicDataViewDefaultView

{

get

{

DataViewdefaultView=this.defaultView;

if(defaultView==null)

{

if(this.dataSet!=null)

{

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

}

else

{

defaultView=newDataView(this,true);

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

}

defaultView=pareExchange<DataView>(refthis.defaultView,defaultView,null);

if(defaultView==null)

{

defaultView=this.defaultView;

}

}

returndefaultView;

}

}

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

publicclassDataView:MarshalByValueComponent,IBindingListView,IBindingList,IList,ICollection,IEnumerable,ITypedList,ISupportInitializeNotification,ISupportInitialize

忽悠:

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

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

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

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

publicclassMDataTable:IDataReader,IEnumerable,ponentModel.IListSource

实现接口:

publicIListGetList()

{

returnRows;

}

接着忽悠:

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

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

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

publicclassDataRowView: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接口,有很多方法:

publicinterfaceICustomTypeDescriptor

{

//Methods

AttributeCollectionGetAttributes();

stringGetClassName();

stringGetComponentName();

TypeConverterGetConverter();

EventDescriptorGetDefaultEvent();

PropertyDescriptorGetDefaultProperty();

objectGetEditor(TypeeditorBaseType);

EventDescriptorCollectionGetEvents();

EventDescriptorCollectionGetEvents(Attribute[]attributes);

PropertyDescriptorCollectionGetProperties();

PropertyDescriptorCollectionGetProperties(Attribute[]attributes);

objectGetPropertyOwner(PropertyDescriptorpd);

}

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

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

PropertyDescriptorCollectionICustomTypeDescriptor.GetProperties(Attribute[]attributes)

{

if(this.dataView.Table==null)

{

returnzeroPropertyDescriptorCollection;

}

returnthis.dataView.Table.GetPropertyDescriptorCollection(attributes);

}

继续深入:

internalPropertyDescriptorCollectionGetPropertyDescriptorCollection(Attribute[]attributes)

{

if(this.propertyDescriptorCollectionCache==null)

{

intcount=this.Columns.Count;

intnum4=this.ChildRelations.Count;

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

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

{

properties[i]=newDataColumnPropertyDescriptor(this.Columns[i]);

}

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

{

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

}

this.propertyDescriptorCollectionCache=newPropertyDescriptorCollection(properties);

}

returnthis.propertyDescriptorCollectionCache;

}

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

那DataColumnPropertyDescriptor是什么?继续深入:

internalDataColumnPropertyDescriptor(DataColumndataColumn):base(dataColumn.ColumnName,null)

{

this.column=dataColumn;

}

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

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

1:继承实现接口方法。

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

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

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

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

1:MDataTable继承IListSource接口实现

#regionIListSource成员

publicboolContainsListCollection

{

get

{

returntrue;

}

}

publicIListGetList()

{

returnRows;

}

#endregion

2:MDataRow继承ICustomTypeDescriptor接口实现

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

自定义属性描述类MDataProperty internalclassMDataProperty:ponentModel.PropertyDescriptor

{

privateMDataCellcell=null;

publicMDataProperty(MDataCellmdc,Attribute[]attrs)

:base(mdc._CellStruct.ColumnName,attrs)

{

cell=mdc;

}

publicoverrideboolCanResetValue(objectcomponent)

{

returnfalse;

}

publicoverrideTypeComponentType

{

get

{

returntypeof(MDataCell);

}

}

publicoverrideobjectGetValue(objectcomponent)

{

return((MDataRow)component)[cell._CellStruct.ColumnName].Value;

}

publicoverrideboolIsReadOnly

{

get

{

returnfalse;

}

}

publicoverrideTypePropertyType

{

get{returncell._CellStruct.ValueType;}

}

publicoverridevoidResetValue(objectcomponent)

{

}

publicoverridevoidSetValue(objectcomponent,objectvalue)

{

cell.Value=value;

}

publicoverrideboolShouldSerializeValue(objectcomponent)

{

returntrue;

}

publicoverrideboolIsBrowsable

{

get

{

returntrue;

}

}

}

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

intindex=0;

PropertyDescriptorCollectionproperties;

publicPropertyDescriptorCollectionGetProperties(Attribute[]attributes)

{

if(index==1)

{

returnproperties;

}

index++;

properties=newPropertyDescriptorCollection(null);

foreach(MDataCellmdcinthis)

{

properties.Add(newMDataProperty(mdc,null));

}

returnproperties;

}

OK,此至,MDataTable顺利完成了对Winform下DataGridView的支持。本文原标题:CYQ.Data 轻量数据层之路 MDataTable绑定Winform之DataGridView 原理高级篇(三十一)

四、总结

微软很强大,MB的Silverlight不支持DataTable的绑定,难道我又要去追随?研究其绑定本质?

不追了,MDataTable增加了ToJson方法和ToList<实体>方法,可直接用json传过去再用反json系列化解析成List<实体>型就可以直接绑定了。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。