彩票走势图

关于模板控件如何实现多数据源绑定的问题

转帖|其它|编辑:郝浩|2010-11-26 15:07:11.000|阅读 733 次

概述:在读Clinglingboy的asp.net控件开发基础(18)时,Clinglingboy对其进行了重点讲解。可是我感觉在如何将具有IListSource接口的数据源最终转化为DataView说的还不是十分清楚,下面我这一部分再详细的说一下。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

  在读Clinglingboy的asp.net控件开发基础(18)时,Clinglingboy对其进行了重点讲解。可是我感觉在如何将具有IListSource接口的数据源最终转化为DataView说的还不是十分清楚,下面我这一部分再详细的说一下。

  首先还是贴一下关键的DataSourceHelper类

  public class DataSourceHelper
  {
  public static object ResolveDataSource(object dataSource, string dataMember)
  {
如果数据源为空,则返回空值#region 如果数据源为空,则返回空值

   if (dataSource == null)
  return null;

   #endregion

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

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

   #endregion

   如果数据源不为空,且为IListSource类型,则返回IListSource#region 如果数据源不为空,且为IListSource类型,则返回IListSource

   else if (dataSource is IListSource)
  {
  IList list = null;
  IListSource listSource = (IListSource)dataSource;
  list = listSource.GetList();
  判断是否为IList对象集合的值#region 判断是否为IList对象集合的值
  if (listSource.ContainsListCollection)
  {
  //提供发现可绑定列表架构的功能,其中可用于绑定的属性不同于要绑定到的对象的公共属性
  ITypedList typedList = (ITypedList)list;
  //返回表示用于绑定数据的每项上属性集合

  //PropertyDescriptorCollection propDescCol =
  // typedList.GetItemProperties(new PropertyDescriptor[0]); //was (null)
  PropertyDescriptorCollection propDesCol=new PropertyDescriptorCollection();
  //如果属性说明符数目为0
  if (propDescCol.Count == 0)
  throw new Exception("ListSource without DataMembers");

   PropertyDescriptor propDesc = null;

   判断dataMember字符数给propDesc赋值#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");

  object listitem = list[0];

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

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

   return (IEnumerable)member;
  }
  else
  //若不包含Ilist集合,则直接返回
  return (IEnumerable)list; //robcamer added (IEnumerable)

   #endregion
  }

   #endregion
  return null;

   }
  }

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

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

  这里像Array、ArrayList、SqlDataReader、DataView等都直接或者间接的实现了IEnumerable接口。

  (2)如果传入的类型非IEnumerable,那么代码会判断数据源是否实现了IListSource接口,因为如果实现了IListSource接口,那么我们同样可以利用此接口的GetList方法返回一个IList,而IList继承IEnumerable,同样可以进行数据绑定。当然如果数据源没有实现IEnumerable和IListSource,数据源就不可绑定。这里像DataTable、DataSet都实现了IListSource接口。

  DataTable实现的GetList方法

  IList IListSource.GetList()
  {
  return this.DefaultView;
  }

  返回了一个DataView
  DataSet实现的GetList方法

  IList IListSource.GetList()
  {
  return this.DefaultViewManager;
  }

  返回了一个DataViewManager。

  通过判断IListSource中的ContainsListCollection,我们可以知道包含多个DataTable的DataSet还是只有一个DataTable,对于后者,由于已经通过GetList方法得到了它的DataView,而DataView又实现了IEnumerable接口,问题也解决了。

  问题现在集中到如何处理DataSet的数据源,我们来看一下DataViewManager类,除了几个public的属性,还有一个DataViewManagerListItemTypeDescriptor类型的Item值得我们注意,后面会讲解此类。同时DataViewManager类实现了ITypedList接口,接下来利用ITypedList.GetItemProperties(object)得到PropertyDescriptorCollection.

  我们看一下ITypedList.GetItemProperties(object)的代码,其中关键一句

  return ((ICustomTypeDescriptor) new DataViewManagerListItemTypeDescriptor(this)).GetProperties();

  看来DataViewManagerListItemTypeDescriptor的GetProperties方法可以得到PropertyDescriptorCollection。此类是Framework的一个内部类,实现了ICustomTypeDescriptor接口。

  那么ICustomTypeDescriptor是做什么用的呢。我们来看一下msdn:

  ICustomTypeDescriptor 使对象得以提供有关自身的类型信息。通常,当对象需要动态类型信息时使用此接口。相反,TypeDescriptor 提供从元数据获得的静态类型信息。

  大家可能对这句话不太明白,我解释一下,这里我用PropertyGrid举例,不熟悉的可以在网上查,实际上我感觉PropertyGrid在和某个类绑定的时候,默认的是用TypeDescriptor 提供从元数据获得的静态类型信息。如下图

  但是有些情况,你需要用到 PropertyGrid 去绑定一个属性/值的集合,但是这个属性/值的集合并不适合写成一个固定的类。

  比如你想用 PropertyGrid 绑定XML 里的数据。或者数据库的某个表。

  假设你有 1000 个XML 文件,每个 XML 所取到的属性集合各不一样,你不可能为每个XML 文件都写一个类 。

  或者你的某个数据表有1000 条记录,该表有 a 字段的值表示属性名称, b字段的值表示属性值,你不可能写一个类,定义1000个属性。

  这时候,我们就希望是否能够将一个动态的属性/值的集合与Property 绑定。通过实现ICustomTypeDescriptor,我们就可以完成动态的属性/值的集合与Property 绑定。这里参考了PropertyGrid 绑定动态的属性与值的集合文章,这篇文章对大家理解ICustomTypeDescriptor会有很大的帮助,文章的代码是VB2005,我用c#2003重新写了一下,这两段代码我会在文章后面给出下载,建议大家先读这篇文章以帮助理解。我把这篇文章的几个类的关键部分列出来。

  public class XProp
  {
  private string theName;
  private object theValue;
  public string Name
  {
  get
  {
  return this.theName;
  }
  set
  {
  this.theName = value;
  }
  }
  public object Value
  {
  get
  {
  return this.theValue;
  }
  set
  {
  this.theValue = value;
  }
  }
  public override string ToString()
  {
  return "Name: " +Name +",Value: "+Value;
  }

   public XProp()
  {
  this.theName = "";
  this.theValue = null;
  }

   }

  public class XPropDescriptor:PropertyDescriptor
  {
  private XProp theProp;
  public override Type ComponentType
  {
  get
  {
  return this.GetType();
  }
  }
  public override bool IsReadOnly
  {
  get
  {
  return false;
  }
  }
  public override Type PropertyType
  {
  get
  {
  return this.theProp.Value.GetType();
  }
  }
  public XPropDescriptor(XProp prop, Attribute[] attrs) : base(prop.Name, attrs)
  {
  this.theProp = prop;
  }
  public override bool CanResetValue(object component)
  {
  return false;
  }
  public override object GetValue(object component)
  {
  return this.theProp.Value;
  }
  public override void ResetValue(object component)
  {
  }
  public override void SetValue(object component, object value)
  {
  this.theProp.Value = value;
  }
  public override bool ShouldSerializeValue(object component)
  {
  return false;
  }

   }public class XProps:CollectionBase,ICustomTypeDescriptor
 {
  public XProps()
  {
 //
  // TODO: 在此处添加构造函数逻辑
//
 }
 IList实现#region IList实现
 public int Add(XProp prop)
  {
  return base.List.Add(prop);
  }
  public XProp FindXProp(string name)
  {
  name = name.Trim().ToLower();
  foreach (XProp prop in base.List)
  {
  if (prop.Name.ToLower() == name)
  {
  return prop;
  }
  return null;
  }
  public void Insert(int index, XProp prop)
  {
  base.List.Insert(index, prop);
  }
  public void Remove(XProp prop)
  {
  base.List.Remove(prop);
  }
  public XProp this[int index]
  {
  get
  {
  return (XProp) base.List[index];
  }
  set
  {
  base.List[index] = value;
  }
 }
  #endregion

   ICustomTypeDescriptor实现#region ICustomTypeDescriptor实现
  public AttributeCollection GetAttributes()
  {
  return TypeDescriptor.GetAttributes(this, true);
  }
  public string GetClassName()
  {
  return TypeDescriptor.GetClassName(this, true);
  }
  public string GetComponentName()
  {
  return TypeDescriptor.GetClassName(this, true);
  }

   public TypeConverter GetConverter()
  {
  return TypeDescriptor.GetConverter(this, true);
  }
  public EventDescriptor GetDefaultEvent()
  {
  return TypeDescriptor.GetDefaultEvent(this, true);
  }
  public PropertyDescriptor GetDefaultProperty()
  {
  return TypeDescriptor.GetDefaultProperty(this, true);
  }
  public object GetEditor(Type editorBaseType)
  {
  return TypeDescriptor.GetEditor(this, editorBaseType, true);
  }
  public EventDescriptorCollection GetEvents()
  {
  return TypeDescriptor.GetEvents(this, true);
  }
  public EventDescriptorCollection GetEvents(Attribute[] attributes)
  {
  return TypeDescriptor.GetEvents(this, attributes, true);
  }
  public PropertyDescriptorCollection GetProperties()
  {
  return TypeDescriptor.GetProperties(this, true);
  }
  public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
  {
  PropertyDescriptor[] props = new PropertyDescriptor[this.Count + 1];
  int count = this.Count - 1;
  for (int i = 0; i <= count; i++)
  {
  props[i] = new XPropDescriptor(this[i], attributes);
  }
  return new PropertyDescriptorCollection(props);
  }
  public object GetPropertyOwner(PropertyDescriptor pd)
  {
  return this;
  }
  #endregion
  public override string ToString()
  {
  StringBuilder sbld = new StringBuilder();
  int count = this.Count - 1;
  for (int i = 0; i <= count; i++)
  {
  sbld.Append("[" + i + "] " + this[i].ToString() + "\r\n");
  }
  return sbld.ToString();
  }

   }

  回到问题上来,在我们实现了ICustomTypeDescriptor,不需要和PropertyGrid绑定,我们可以得到一个PropertyDescriptorCollection。那么就来具体看看对比。

  其中上文的XProp --> DataTable

   XProps 的GetProperties方法--> ((ITypedList) DataViewManager).GetItemProperties方法

   XPropDescriptor--> DataTablePropertyDescriptor

  大家会看到((ITypedList) DataViewManager).GetItemProperties方法返回了DataTablePropertyDescriptor的PropertyDescriptorCollection集合;XProps的GetProperties方法返回了XPropDescriptor的PropertyDescriptorCollection集合

  在DataTablePropertyDescriptor会有一个DataTable的属性,并且该类复写了GetValue方法,取得值,这个和XPropDescriptor中有XProp属性,且复写了GetValue方法是一致的。唯一不同的是XPropDescriptor的GetValue方法只是将具体的XProp的Value返回,而DataTablePropertyDescriptor中的GetValue方法又利用DataTable进一步操作返回了DataView。

  我们现在知道ITypedList.GetItemProperties(object)是怎么得到PropertyDescriptorCollection(确切的说是DataTablePropertyDescriptor),我们接着利用propDesc = propDescCol.Find(dataMember, true)去在集合中查找名字为dataMember值也就是具体的表名,以返回待操作的DataTablePropertyDescriptor。在((ICustomTypeDescriptor) new DataViewManagerListItemTypeDescriptor(this)).GetProperties()方法建立集合的时候采用了表名作为名值对的名,大家可以对照代码看看。接下来再看这段代码

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

  list是什么?实际上是我们在前面得到的DataViewManager.IListSource listSource = (IListSource)dataSource;

  list = listSource.GetList();

  由于DataViewManager实现了IList接口,因此我们可以用list[index]的形式取得具体的元素,这里我们看到是取得了item的值,还记得我们前面让大家留意DataViewManager的Item属性,实际上它就是一个DataViewManagerListItemTypeDescriptor。propDesc是一个DataTablePropertyDescriptor,来看一下他的GetValue(object)代码

  public override object GetValue(object component)
  {
  DataViewManagerListItemTypeDescriptor descriptor = (DataViewManagerListItemTypeDescriptor) component;
  return descriptor.GetDataView(this.table);
  }

  而DataViewManagerListItemTypeDescriptor的GetDataView的代码

  internal DataView GetDataView(DataTable table)
  {
  DataView view = new DataView(table);
  view.SetDataViewManager(this.dataViewManager);
  return view;
  }

  实际上这一步就是利用DataTable构建DataView,我觉得也可以用其他的方法完成,给DataViewManagerListItemTypeDescriptor增加一个内部的GetDataView方法反而弱化了TypeDescriptor的功能。

  到这里,我们就可以返回一个(IEnumberable)DataView了。
 

 


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:博客转载

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP