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获得可绑定的数据。
相关阅读 更多 +