Silverlight根据Xml数据动态生成类绑定到DataGrid
时间:2011-05-21 来源:J. W.
下面的代码扩展了IEnumerable接口,让此接口可以将普通的IEnumerable集合通过Emit转化成为实体类集合,这将是动态生成类的关键:
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)
{
throw new ArgumentException("IDictionary entry cannot be null");
}
object row = Activator.CreateInstance(objectType);
foreach (DictionaryEntry pair in firstDict)
{
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.Public |
MethodAttributes.SpecialName |
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,
MethodAttributes.Public |
MethodAttributes.SpecialName |
MethodAttributes.HideBySig,
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);
}
}
当得到一个Xml数据源之后,用Linq To Xml或XmlReader操作此数据源,生成一个IEnumarable<IDictionary>类型的对象。其中IDictionary是一个键值对集合,这个键值对包含了一个字段的字段名和对应的值,多个这样的IDictionary(键值对集合)组成一个数据集合IEnumarable<IDictionary>。对IEnumarable<IDictionary>调用扩展方法ToDataSource获得可绑定的数据。
相关阅读 更多 +










