轉(zhuǎn)帖|其它|編輯:郝浩|2010-11-26 15:07:11.000|閱讀 733 次
概述:在讀Clinglingboy的asp.net控件開發(fā)基礎(chǔ)(18)時(shí),Clinglingboy對(duì)其進(jìn)行了重點(diǎn)講解。可是我感覺在如何將具有IListSource接口的數(shù)據(jù)源最終轉(zhuǎn)化為DataView說的還不是十分清楚,下面我這一部分再詳細(xì)的說一下。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
在讀Clinglingboy的asp.net控件開發(fā)基礎(chǔ)(18)時(shí),Clinglingboy對(duì)其進(jìn)行了重點(diǎn)講解。可是我感覺在如何將具有IListSource接口的數(shù)據(jù)源最終轉(zhuǎn)化為DataView說的還不是十分清楚,下面我這一部分再詳細(xì)的說一下。
首先還是貼一下關(guān)鍵的DataSourceHelper類
public class DataSourceHelper
{
public static object ResolveDataSource(object dataSource, string dataMember)
{
如果數(shù)據(jù)源為空,則返回空值#region 如果數(shù)據(jù)源為空,則返回空值
if (dataSource == null)
return null;
#endregion
如果數(shù)據(jù)源不為空,且為IEnumerable類型,則返回IEnumerable#region 如果數(shù)據(jù)源不為空,且為IEnumerable類型,則返回IEnumerable
if (dataSource is IEnumerable)
{
return (IEnumerable)dataSource;
}
#endregion
如果數(shù)據(jù)源不為空,且為IListSource類型,則返回IListSource#region 如果數(shù)據(jù)源不為空,且為IListSource類型,則返回IListSource
else if (dataSource is IListSource)
{
IList list = null;
IListSource listSource = (IListSource)dataSource;
list = listSource.GetList();
判斷是否為IList對(duì)象集合的值#region 判斷是否為IList對(duì)象集合的值
if (listSource.ContainsListCollection)
{
//提供發(fā)現(xiàn)可綁定列表架構(gòu)的功能,其中可用于綁定的屬性不同于要綁定到的對(duì)象的公共屬性
ITypedList typedList = (ITypedList)list;
//返回表示用于綁定數(shù)據(jù)的每項(xiàng)上屬性集合
//PropertyDescriptorCollection propDescCol =
// typedList.GetItemProperties(new PropertyDescriptor[0]); //was (null)
PropertyDescriptorCollection propDesCol=new PropertyDescriptorCollection();
//如果屬性說明符數(shù)目為0
if (propDescCol.Count == 0)
throw new Exception("ListSource without DataMembers");
PropertyDescriptor propDesc = null;
判斷dataMember字符數(shù)給propDesc賦值#region 判斷dataMember字符數(shù)給propDesc賦值
//獲取屬性描述符
//若不指定dataMember屬性則獲取默認(rèn)數(shù)據(jù)成員
if ((dataMember == null) || (dataMember.Length < 1))
{
propDesc = propDescCol[0];
}
else
//嘗試在屬性集合中尋找數(shù)據(jù)成員
propDesc = propDescCol.Find(dataMember, true);
#endregion
if (propDesc == null)
throw new Exception("ListSource missing DataMember");
object listitem = list[0];
//獲取組件屬性當(dāng)前值
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)如果傳入的數(shù)據(jù)源類型是IEnumerable的話,可以直接返回
if (dataSource is IEnumerable)
{
return (IEnumerable)dataSource;
}
這里像Array、ArrayList、SqlDataReader、DataView等都直接或者間接的實(shí)現(xiàn)了IEnumerable接口。
(2)如果傳入的類型非IEnumerable,那么代碼會(huì)判斷數(shù)據(jù)源是否實(shí)現(xiàn)了IListSource接口,因為如果實(shí)現(xiàn)了IListSource接口,那么我們同樣可以利用此接口的GetList方法返回一個(gè)IList,而IList繼承IEnumerable,同樣可以進(jìn)行數(shù)據(jù)綁定。當(dāng)然如果數(shù)據(jù)源沒有實(shí)現(xiàn)IEnumerable和IListSource,數(shù)據(jù)源就不可綁定。這里像DataTable、DataSet都實(shí)現(xiàn)了IListSource接口。
DataTable實(shí)現(xiàn)的GetList方法
IList IListSource.GetList()
{
return this.DefaultView;
}
返回了一個(gè)DataView
DataSet實(shí)現(xiàn)的GetList方法
IList IListSource.GetList()
{
return this.DefaultViewManager;
}
返回了一個(gè)DataViewManager。
通過判斷IListSource中的ContainsListCollection,我們可以知道包含多個(gè)DataTable的DataSet還是只有一個(gè)DataTable,對(duì)于后者,由于已經(jīng)通過GetList方法得到了它的DataView,而DataView又實(shí)現(xiàn)了IEnumerable接口,問題也解決了。
問題現(xiàn)在集中到如何處理DataSet的數(shù)據(jù)源,我們來看一下DataViewManager類,除了幾個(gè)public的屬性,還有一個(gè)DataViewManagerListItemTypeDescriptor類型的Item值得我們注意,后面會(huì)講解此類。同時(shí)DataViewManager類實(shí)現(xiàn)了ITypedList接口,接下來利用ITypedList.GetItemProperties(object)得到PropertyDescriptorCollection.
我們看一下ITypedList.GetItemProperties(object)的代碼,其中關(guān)鍵一句
return ((ICustomTypeDescriptor) new DataViewManagerListItemTypeDescriptor(this)).GetProperties();
看來DataViewManagerListItemTypeDescriptor的GetProperties方法可以得到PropertyDescriptorCollection。此類是Framework的一個(gè)內(nèi)部類,實(shí)現(xiàn)了ICustomTypeDescriptor接口。
那么ICustomTypeDescriptor是做什么用的呢。我們來看一下msdn:
ICustomTypeDescriptor 使對(duì)象得以提供有關(guān)自身的類型信息。通常,當(dāng)對(duì)象需要?jiǎng)討B(tài)類型信息時(shí)使用此接口。相反,TypeDescriptor 提供從元數(shù)據(jù)獲得的靜態(tài)類型信息。
大家可能對(duì)這句話不太明白,我解釋一下,這里我用PropertyGrid舉例,不熟悉的可以在網(wǎng)上查,實(shí)際上我感覺PropertyGrid在和某個(gè)類綁定的時(shí)候,默認(rèn)的是用TypeDescriptor 提供從元數(shù)據(jù)獲得的靜態(tài)類型信息。如下圖
但是有些情況,你需要用到 PropertyGrid 去綁定一個(gè)屬性/值的集合,但是這個(gè)屬性/值的集合并不適合寫成一個(gè)固定的類。
比如你想用 PropertyGrid 綁定XML 里的數(shù)據(jù)。或者數(shù)據(jù)庫的某個(gè)表。
假設(shè)你有 1000 個(gè)XML 文件,每個(gè) XML 所取到的屬性集合各不一樣,你不可能為每個(gè)XML 文件都寫一個(gè)類 。
或者你的某個(gè)數(shù)據(jù)表有1000 條記錄,該表有 a 字段的值表示屬性名稱, b字段的值表示屬性值,你不可能寫一個(gè)類,定義1000個(gè)屬性。
這時(shí)候,我們就希望是否能夠?qū)⒁粋€(gè)動(dòng)態(tài)的屬性/值的集合與Property 綁定。通過實(shí)現(xiàn)ICustomTypeDescriptor,我們就可以完成動(dòng)態(tài)的屬性/值的集合與Property 綁定。這里參考了PropertyGrid 綁定動(dòng)態(tài)的屬性與值的集合文章,這篇文章對(duì)大家理解ICustomTypeDescriptor會(huì)有很大的幫助,文章的代碼是VB2005,我用c#2003重新寫了一下,這兩段代碼我會(huì)在文章后面給出下載,建議大家先讀這篇文章以幫助理解。我把這篇文章的幾個(gè)類的關(guān)鍵部分列出來。
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: 在此處添加構(gòu)造函數(shù)邏輯
//
}
IList實(shí)現(xiàn)#region IList實(shí)現(xiàn)
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實(shí)現(xiàn)#region ICustomTypeDescriptor實(shí)現(xiàn)
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();
}
}
回到問題上來,在我們實(shí)現(xiàn)了ICustomTypeDescriptor,不需要和PropertyGrid綁定,我們可以得到一個(gè)PropertyDescriptorCollection。那么就來具體看看對(duì)比。
其中上文的XProp --> DataTable
XProps 的GetProperties方法--> ((ITypedList) DataViewManager).GetItemProperties方法
XPropDescriptor--> DataTablePropertyDescriptor
大家會(huì)看到((ITypedList) DataViewManager).GetItemProperties方法返回了DataTablePropertyDescriptor的PropertyDescriptorCollection集合;XProps的GetProperties方法返回了XPropDescriptor的PropertyDescriptorCollection集合
在DataTablePropertyDescriptor會(huì)有一個(gè)DataTable的屬性,并且該類復(fù)寫了GetValue方法,取得值,這個(gè)和XPropDescriptor中有XProp屬性,且復(fù)寫了GetValue方法是一致的。唯一不同的是XPropDescriptor的GetValue方法只是將具體的XProp的Value返回,而DataTablePropertyDescriptor中的GetValue方法又利用DataTable進(jìn)一步操作返回了DataView。
我們現(xiàn)在知道ITypedList.GetItemProperties(object)是怎么得到PropertyDescriptorCollection(確切的說是DataTablePropertyDescriptor),我們接著利用propDesc = propDescCol.Find(dataMember, true)去在集合中查找名字為dataMember值也就是具體的表名,以返回待操作的DataTablePropertyDescriptor。在((ICustomTypeDescriptor) new DataViewManagerListItemTypeDescriptor(this)).GetProperties()方法建立集合的時(shí)候采用了表名作為名值對(duì)的名,大家可以對(duì)照代碼看看。接下來再看這段代碼
object listitem = list[0];
//獲取組件屬性當(dāng)前值
object member = propDesc.GetValue(listitem);
list是什么?實(shí)際上是我們在前面得到的DataViewManager.IListSource listSource = (IListSource)dataSource;
list = listSource.GetList();
由于DataViewManager實(shí)現(xiàn)了IList接口,因此我們可以用list[index]的形式取得具體的元素,這里我們看到是取得了item的值,還記得我們前面讓大家留意DataViewManager的Item屬性,實(shí)際上它就是一個(gè)DataViewManagerListItemTypeDescriptor。propDesc是一個(gè)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;
}
實(shí)際上這一步就是利用DataTable構(gòu)建DataView,我覺得也可以用其他的方法完成,給DataViewManagerListItemTypeDescriptor增加一個(gè)內(nèi)部的GetDataView方法反而弱化了TypeDescriptor的功能。
到這里,我們就可以返回一個(gè)(IEnumberable)DataView了。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:博客轉(zhuǎn)載