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

本文涉及的产品
云解析DNS-重点域名监控,免费拨测 20万次(价值200元)
简介:   前言  在上篇写了篇 实战系列之天气预报实时采集 ,有个别同志认为没技术含量,也许正如所说。只是人各有看法,当我写出一篇文章时,我只是希望:1:如果你还不懂,请看写法,了解想法。2:如果你已懂,略过写法,请看想法。

  前言

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

只是人各有看法,当我写出一篇文章时,我只是希望:
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:先实现自定义属性描述类

自定义属性描述类MDataProperty
internal   class  MDataProperty : System.ComponentModel.PropertyDescriptor
    {
        
private  MDataCell cell  =   null ;
        
public  MDataProperty(MDataCell mdc, Attribute[] attrs)
            : 
base (mdc._CellStruct.ColumnName, attrs)
        {
            cell 
=  mdc;
        }

        
public   override   bool  CanResetValue( object  component)
        {
            
return   false ;
        }

        
public   override  Type ComponentType
        {
            
get
            {
                
return   typeof (MDataCell);
            }
        }
        
public   override   object  GetValue( object  component)
        {
            
return  ((MDataRow)component)[cell._CellStruct.ColumnName].Value;
           
        }

        
public   override   bool  IsReadOnly
        {
            
get
            {
                
return   false ;
            }
        }

        
public   override  Type PropertyType
        {
            
get  {  return  cell._CellStruct.ValueType; }
        }

        
public   override   void  ResetValue( object  component)
        {

        }

        
public   override   void  SetValue( object  component,  object  value)
        {
            cell.Value 
=  value;
        }

        
public   override   bool  ShouldSerializeValue( object  component)
        {
            
return   true ;
        }
              
        
public   override   bool  IsBrowsable
        {
            
get
            {
                
return   true ;
            }
        }
    }

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

         int  index  =   0 ;
        PropertyDescriptorCollection properties;
        
public  PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            
if  (index  ==   1 )
            {
                
return  properties;
            }
            index
++ ;
            properties 
=   new  PropertyDescriptorCollection( null );

            
foreach  (MDataCell mdc  in   this )
            {
                properties.Add(
new  MDataProperty(mdc,  null ));
            }
            
return  properties;
        }

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

  四、总结

微软很强大,MB的Silverlight不支持DataTable的绑定,难道我又要去追随?研究其绑定本质?
不追了,MDataTable增加了ToJson方法和ToList
< 实体 > 方法,可直接用json传过去再用反json系列化解析成List < 实体 > 型就可以直接绑定了。
目录
相关文章
|
2月前
|
监控 Cloud Native 测试技术
.NET技术深度解析:现代企业级开发指南
每日激励:“不要一直责怪过去的自己,他曾经站在雾里也很迷茫”。我是蒋星熠Jaxonic,一名在代码宇宙中探索的极客旅人。从.NET Framework到.NET 8,我深耕跨平台、高性能、云原生开发,践行领域驱动设计与微服务架构,用代码书写技术诗篇。分享架构演进、性能优化与AI融合前沿,助力开发者在二进制星河中逐光前行。关注我,共探技术无限可能!
.NET技术深度解析:现代企业级开发指南
|
9月前
|
传感器 人工智能 物联网
穿戴科技新风尚:智能服装设计与技术全解析
穿戴科技新风尚:智能服装设计与技术全解析
719 85
|
9月前
|
人工智能 API 语音技术
HarmonyOS Next~鸿蒙AI功能开发:Core Speech Kit与Core Vision Kit的技术解析与实践
本文深入解析鸿蒙操作系统(HarmonyOS)中的Core Speech Kit与Core Vision Kit,探讨其在AI功能开发中的核心能力与实践方法。Core Speech Kit聚焦语音交互,提供语音识别、合成等功能,支持多场景应用;Core Vision Kit专注视觉处理,涵盖人脸检测、OCR等技术。文章还分析了两者的协同应用及生态发展趋势,展望未来AI技术与鸿蒙系统结合带来的智能交互新阶段。
586 31
|
9月前
|
编解码 监控 网络协议
RTSP协议规范与SmartMediaKit播放器技术解析
RTSP协议是实时流媒体传输的重要规范,大牛直播SDK的rtsp播放器基于此构建,具备跨平台支持、超低延迟(100-300ms)、多实例播放、高效资源利用、音视频同步等优势。它广泛应用于安防监控、远程教学等领域,提供实时录像、快照等功能,优化网络传输与解码效率,并通过事件回调机制保障稳定性。作为高性能解决方案,它推动了实时流媒体技术的发展。
496 5
|
9月前
|
数据采集 机器学习/深度学习 存储
可穿戴设备如何重塑医疗健康:技术解析与应用实战
可穿戴设备如何重塑医疗健康:技术解析与应用实战
344 4
|
9月前
|
机器学习/深度学习 人工智能 自然语言处理
AI技术如何重塑客服系统?解析合力亿捷AI智能客服系统实践案例
本文探讨了人工智能技术在客服系统中的应用,涵盖技术架构、关键技术和优化策略。通过感知层、认知层、决策层和执行层的协同工作,结合自然语言处理、知识库构建和多模态交互技术,合力亿捷客服系统实现了智能化服务。文章还提出了用户体验优化、服务质量提升和系统性能改进的方法,并展望了未来发展方向,强调其在客户服务领域的核心价值与潜力。
531 6
|
9月前
|
编解码 人工智能 并行计算
基于 Megatron 的多模态大模型训练加速技术解析
Pai-Megatron-Patch 是一款由阿里云人工智能平台PAI 研发的围绕英伟达 Megatron 的大模型训练配套工具,旨在帮助开发者快速上手大模型,打通大模型相关的高效分布式训练、有监督指令微调、下游任务评估等大模型开发链路。本文以 Qwen2-VL 为例,从易用性和训练性能优化两个方面介绍基于 Megatron 构建的 Pai-Megatron-Patch 多模态大模型训练的关键技术
|
9月前
|
监控 负载均衡 安全
静态IP代理与动态IP代理:提升速度与保障隐私的技术解析
本文探讨了静态IP代理和动态IP代理的特性和应用场景。静态IP代理通过高质量服务提供商、网络设置优化、定期更换IP与负载均衡及性能监控提升网络访问速度;动态IP代理则通过隐藏真实IP、增强安全性、绕过封锁和提供独立IP保障用户隐私。结合实际案例与代码示例,展示了两者在不同场景下的优势,帮助用户根据需求选择合适的代理服务以实现高效、安全的网络访问。
328 1
|
9月前
|
机器学习/深度学习 数据采集 自然语言处理
基于Python的情感分析与情绪识别技术深度解析
本文探讨了基于Python的情感分析与情绪识别技术,涵盖基础概念、实现方法及工业应用。文中区分了情感分析与情绪识别的核心差异,阐述了从词典法到深度学习的技术演进,并通过具体代码展示了Transformers架构在细粒度情感分析中的应用,以及多模态情绪识别框架的设计。此外,还介绍了电商评论分析系统的构建与优化策略,包括领域自适应训练和集成学习等方法。未来,随着深度学习和多模态数据的发展,该技术将更加智能与精准。
568 1
|
8月前
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
317 0

推荐镜像

更多
  • DNS