在實際項目中,我們可能會遇到使用者自定義XML模闆字段,根據這個模闆上的字段來顯示相應的字段的值到DataGrid。在這種情況下,需要使用 XmlReader解析擷取這個使用者自定義的XML模闆上有哪些字段,根據這個字段動态的生成一個實體類,之後再為此動态生成的實體類執行個體化,并且生成實 體類集合綁定到DataGrid即可。(注意:平時我們綁定DataGrid是先在代碼裡面聲明了實體類,執行個體化多個實體化類,形成實體類集合,綁定到 DataGrid。可如果使用者自定義XML格式的字段的時候,每次的實體類就不能為靜态的了。必須為動态的才行。)
一、首先我們準備一個XML格式的模闆資料。模拟使用者自定義的XML模闆字段。這裡的XML模闆字段可以自由添改。
<NewDataSet>
<Table TableName='City' TableShowName='城市' >
<Column Name='CityName' ShowName='城市名稱' />
<Column Name='CityTel' ShowName='城市區号' />
<Column Name='CityCounty' ShowName='城市所屬國家' />
</Table>
<Table TableName='User' TableShowName='使用者' >
<Column Name='UserName' ShowName='使用者名' />
<Column Name='UserPwd' ShowName='使用者密碼' />
<Column Name='UserTel' ShowName='使用者電話' />
<Column Name='UserEmail' ShowName='使用者郵箱' />
</NewDataSet>
再聲明一個實體類來儲存字段的Name和顯示名稱ShowName,并且把這些字段存放到List<>中去。
/// <summary>
/// 存放動态表格的字段
/// </summary>
public class GridClass
{
private string _ShowName;
private string _Name;
/// 顯示名稱
public string ShowName
get { return _ShowName; }
set { _ShowName = value; }
}
/// 字段名稱
public string Name
get { return _Name; }
set { _Name = value; }
二、準備好資料之後,我們開始解析這個XML文檔,并且根據此XML文檔生成兩個動态Tabel實體類。這裡我們首先貼出關鍵代碼,根據代碼來解讀:
List<GridClass> gridClassList = new List<GridClass>();//聲明一個GridClass實體類的集合。
using (XmlReader xmlRead = XmlReader.Create(new StringReader(XMLStr)))
{
xmlRead.Read();
while (xmlRead.Read())
{
//擷取到一個TABLE,然後轉化為一個動态的實體類。
gridClassList.Clear();//循環讀取Tabel元素的時候,清空GridClass實體類集合。
xmlRead.ReadToFollowing("Table");//讀取Table的顯示名稱和Tabel的名稱。
string TableShowName = xmlRead.GetAttribute("TableShowName");
string TableName = xmlRead.GetAttribute("TableName");
try
{
using (XmlReader xReader2 = xmlRead.ReadSubtree())//将此Tabel讀取為一個子XmlReader以供下一步使用。
{
while (xReader2.ReadToFollowing("Column"))
{
//循環讀取Column元素,然後擷取到Tabel的字段的顯示名稱和字段名稱。并且添加到gridClassList
string ShowName = xReader2.GetAttribute("ShowName");
string Name = xReader2.GetAttribute("Name");
GridClass gclass = new GridClass() { ShowName = ShowName, Name = Name };
gridClassList.Add(gclass);
}
//聲明一個Dictionary<string, string>的List<>集合
List<Dictionary<string, string>> dicList = new List<Dictionary<string, string>>();
//聲明一個Dictionary<string, string>實體,然後為此實體指派列名為讀取Column元素得到的字段名稱
Dictionary<string, string> dic = new Dictionary<string, string>();
for (int j = 0; j < gridClassList.Count; j++)
dic[gridClassList[j].Name] = "--"+gridClassList[j].Name+"--";
dicList.Add(dic);
//動态生成一個DataGrid,并且綁定資料源
DataGrid dgrid = new DataGrid();
dgrid.HorizontalAlignment = HorizontalAlignment.Left;
dgrid.VerticalAlignment = VerticalAlignment.Top;
dgrid.Margin = new Thickness(20, 5, 0, 0);
dgrid.Width = 960;
dgrid.Name = TableName;
dgrid.ItemsSource = GetEnumerable(dicList).ToDataSource();
this.mainPanel.Children.Add(dgrid);
}
}
catch (Exception ex)
{ }
}
}
}
這裡解析出關鍵的字段值,然後動态生成DataGrid,并且綁定了資料庫。這些操作是不是很熟悉?幾乎和原來綁定資料差不多?關鍵在以下幾句:
//聲明一個Dictionary<string, string>的List<>集合
List<Dictionary<string, string>> dicList = new List<Dictionary<string, string>>();
//聲明一個Dictionary<string, string>實體,然後為此實體指派列名為讀取Column元素得到的字段名稱
Dictionary<string, string> dic = new Dictionary<string, string>();
for (int j = 0; j < gridClassList.Count; j++)
{
dic[gridClassList[j].Name] = "--"+gridClassList[j].Name+"--";
}
dicList.Add(dic);
通過這段代碼我們得到了一個 List<Dictionary<string, string>>格式的Dictionary<string, string>集合。這裡Dictionary的Key值,即為一列字段名,Value為該列的具體值,那麼一個 Dictionary[0],Dictionary[1],Dictionary[2],Dictionary[3],Dictionary[4],Dictionary[5] 即為一行有字段名的資料,整個List<Dictionary>就是一個多行有字段名的資料,這就相當于一個類似于DataTabel的表 了。
三、當然更關鍵的下一句:dgrid.ItemsSource = GetEnumerable(dicList).ToDataSource();這句話肯定是得到了一個類似于List<object>對象 集的東西,才能夠綁定到ItemSource屬性上來。具體是如何得到這個資料集的呢?在這裡暫且先賣一個關子,請看下面源碼:
public IEnumerable<IDictionary> GetEnumerable(List<Dictionary<string, string>> SourceList)
for (int i = 0; i < SourceList.Count; i++)
var dict = new Dictionary<string, string>();
dict = SourceList[i];
yield return dict;
DataSourceCreator.cs
public static class DataSourceCreator
private static readonly Regex PropertNameRegex =
new Regex(@"^[A-Za-z]+[A-Za-z1-9_]*$", RegexOptions.Singleline);
public static List<object> ToDataSource(this IEnumerable<IDictionary> list)
IDictionary firstDict = null;
bool hasData = false;
foreach (IDictionary currentDict in list)
hasData = true;
firstDict = currentDict;
break;
if (!hasData)
return new List<object> { };
if (firstDict == null)
throw new ArgumentException("IDictionary entry cannot be null");
Type objectType = null;
TypeBuilder tb = GetTypeBuilder(list.GetHashCode());
ConstructorBuilder constructor =
tb.DefineDefaultConstructor(
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName);
foreach (DictionaryEntry pair in firstDict)
if (PropertNameRegex.IsMatch(Convert.ToString(pair.Key), 0))
CreateProperty(tb,
Convert.ToString(pair.Key),
pair.Value == null ?
typeof(object) :
pair.Value.GetType());
else
throw new ArgumentException(
@"Each key of IDictionary must be
alphanumeric and start with character.");
objectType = tb.CreateType();
return GenerateArray(objectType, list, firstDict);
private static List<object> GenerateArray(Type objectType, IEnumerable<IDictionary> list, IDictionary firstDict)
var itemsSource = new List<object>();
foreach (var currentDict in list)
if (currentDict == null)
object row = Activator.CreateInstance(objectType);
if (currentDict.Contains(pair.Key))
PropertyInfo property =
objectType.GetProperty(Convert.ToString(pair.Key));
property.SetValue(
row,
Convert.ChangeType(
currentDict[pair.Key],
property.PropertyType,
null),
null);
itemsSource.Add(row);
return itemsSource;
private static TypeBuilder GetTypeBuilder(int code)
AssemblyName an = new AssemblyName("TempAssembly" + code);
AssemblyBuilder assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
an, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("MainModule");
TypeBuilder tb = moduleBuilder.DefineType("TempType" + code
, TypeAttributes.Public |
TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout
, typeof(object));
return tb;
private static void CreateProperty(TypeBuilder tb, string propertyName, Type propertyType)
FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName,
propertyType,
FieldAttributes.Private);
PropertyBuilder propertyBuilder =
tb.DefineProperty(
propertyName, PropertyAttributes.HasDefault, propertyType, null);
MethodBuilder getPropMthdBldr =
tb.DefineMethod("get_" + propertyName,
MethodAttributes.HideBySig,
propertyType, Type.EmptyTypes);
ILGenerator getIL = getPropMthdBldr.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.Emit(OpCodes.Ret);
MethodBuilder setPropMthdBldr =
tb.DefineMethod("set_" + propertyName,
null, new Type[] { propertyType });
ILGenerator setIL = setPropMthdBldr.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, fieldBuilder);
setIL.Emit(OpCodes.Ret);
propertyBuilder.SetGetMethod(getPropMthdBldr);
propertyBuilder.SetSetMethod(setPropMthdBldr);
文轉自程興亮 51CTO部落格,原文連結:http://blog.51cto.com/chengxingliang/821464