轉帖|其它|編輯:郝浩|2010-11-26 15:07:11.000|閱讀 733 次
概述:在讀Clinglingboy的asp.net控件開發基礎(18)時,Clinglingboy對其進行了重點講解??墒俏腋杏X在如何將具有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@fc6vip.cn
文章轉載自:博客轉載