? ? ? ? 使用Silverlight开发前台页面,需要将后台查询回的集合绑定到前台的DataGrid上。
? ? ? ? 一般情况下,我们都有定义好的实体类Po,然后可以.xaml文件中固定绑定Po的成员变量到DataGrid的列上,当取到实体集合时直接将 dataGrid.itemsource = List<Po> 即可。
? ? ? ? 但有些时候,我们并不知道返回的集合中的实体是什么类型,无法预先定义PO,那么该如何动态绑定列和集合呢?
? ? ? ? ?想到一个方法就是在拿到集合后通过反射动态的创建PO类,动态添加public属性,并动态绑定到DataGrid Column。然后再绑定实体集合就可实现需求。
? ? ? ? ?首先在工程中添加动态类型工厂类 DynamicTypeBuilder:
class="c#" name="code"> public class DynamicTypeBuilder
{
TypeBuilder tb;
/// <summary>
/// 构造函数
/// </summary>
/// <param name="typeNm">动态类型的名称</param>
public DynamicTypeBuilder(string typeNm)
{
// 在 Silverlight 中 AssemblyBuilderAccess 没有 RunAndSave
AssemblyBuilder ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName("TempAssembly"), AssemblyBuilderAccess.Run);
ModuleBuilder mb = ab.DefineDynamicModule("TempModule");
this.tb = mb.DefineType(typeNm, TypeAttributes.Public);
}
/// <summary>
/// 添加一个public的可读写属性,并且会创建对应的名为 propertyNm + "Field" 的私有字段
/// </summary>
/// <param name="propertyNm"></param>
/// <param name="type"></param>
public void AppendPublicProperty(string propertyNm, Type type)
{
this.AppendPublicProperty(propertyNm, type, true, true);
}
/// <summary>
/// 添加一个public属性,并且会创建对应的名为 propertyNm + "Field" 的私有字段
/// </summary>
/// <param name="propertyNm"></param>
/// <param name="type"></param>
/// <param name="canGet">是否实现getter</param>
/// <param name="canSet">是否实现setter</param>
public void AppendPublicProperty(string propertyNm, Type type, bool canGet, bool canSet)
{
FieldBuilder field = this.tb.DefineField(string.Format("{0}Field", propertyNm), type, FieldAttributes.Private);
PropertyBuilder property = tb.DefineProperty(propertyNm, PropertyAttributes.HasDefault, type, null);
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig;
if (canGet)
{
MethodBuilder getAccessor = tb.DefineMethod(string.Format("get_{0}", propertyNm), getSetAttr, type, Type.EmptyTypes);
ILGenerator getIL = getAccessor.GetILGenerator();
// For an instance property, argument default is the instance. Load the
// instance, then load the private field and return, leaving the
// field value on the stack.
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, field);
getIL.Emit(OpCodes.Ret);
property.SetGetMethod(getAccessor);
}
if (canSet)
{
MethodBuilder setAccessor = tb.DefineMethod(string.Format("set_{0}", propertyNm), getSetAttr, null, new Type[] { type });
setAccessor.DefineParameter(1, ParameterAttributes.None, "value");
ILGenerator setIL = setAccessor.GetILGenerator();
// Load the instance and then the numeric argument, then store the
// argument in the field.
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, field);
setIL.Emit(OpCodes.Ret);
property.SetSetMethod(setAccessor);
}
}
/// <summary>
/// 在添加完各个 public 属性之后,调用此方法以完成对动态类型的定义并加载之,
/// 此后通过 Activator.CreateInstance() 便可实例化动态类型
/// </summary>
/// <returns></returns>
public Type CreateDynamicType()
{
return this.tb.CreateType();
}
}
?
? ? 有了它我们就可以动态创建类了。
? ? ??
DynamicTypeBuilder dyClass = new DynamicTypeBuilder("dy");//创建动态类,dy可以随便替换
datagrid.Columns.Clear();//清空datagrid的已有列
.......
//ColInfos为已经取到的列信息集合
foreach (ColInfo colInfo in colInfos)
{
String name = colInfo.name;//列绑定名
String title = colInfo.title;//列显示名
DataGridTextColumn dtc = new DataGridTextColumn();//动态创建列,完成绑定
dtc.Header = name;
dtc.Binding = new Binding("_" + name);
this.datagrid.Columns.Add(dtc);//添加列
dyClass.AppendPublicProperty("_" + name, typeof(string));//同时动态添加公共属性到自定义类
}
Type dyType = dyClass.CreateDynamicType();//创建自定义类
........
//构造绑定DataGrid ItemSource的集合
List<Object> datas = new List<Object>();
var po = Activator.CreateInstance(dyType);//创建自定义类实例
PropertyInfo property = dyType.GetProperty("_" + colInfos[i].name);
property.SetValue(po, [value], null);
datas.add(po);
dataGrid.itemsource = datas
}
?