所以我有这个Generic类型的类,它使用System.Reflection从类中获取所有公共变量并将它们呈现为控件。
但是我需要能够将这些变量用作控件的DataBindings,这样当控件接收输入时,该输入会保存到相应的变量中。
这是我到目前为止所得到的,但我得到的是“不能绑定到属性或列”。错误。
班级:
public class ComponentControl<T> where T : Component
{
private T component;
public ComponentControl(T component)
{
this.component = component;
}
}
不能工作的部分:
foreach (var f in type.GetFields().Where(f => f.IsPublic))
{
TextBox control = new TextBox();
Binding binding = new Binding("Text", component, f.Name, false, DataSourceUpdateMode.OnPropertyChanged);
control.DataBindings.Add(binding);
}
答案 0 :(得分:0)
我认为你只能绑定到自定义对象的属性,而不是字段。这似乎有点矫枉过正,但如果有一种更简单的方法,我相信有人会纠正我..
假设您不想将字段更改为属性,并且您确实想要使用绑定,则可以生成一种要绑定的DTO。例如,以下是绑定方式,因此请使用proxyType而不是实际类型。
ComponentControl<int> component = new ComponentControl<int>() { A = "A", B = 1, C = 2 };
Type type = component.GetType();
dynamic proxyType = DynamicProxyGenerator.GetInstanceFor<ComponentControl<int>>(component);
foreach (var f in type.GetFields().Where(f => f.IsPublic))
{
TextBox control = new TextBox();
Binding binding = new Binding("Text", proxyType, f.Name, false, DataSourceUpdateMode.OnPropertyChanged);
control.DataBindings.Add(binding);
}
以下是DynamicProxyGenerator
生成该代码的代码。
public static class DynamicProxyGenerator
{
public static object GetInstanceFor<T>(T toBind)
{
Type typeOfT = typeof(T);
AssemblyName assName = new AssemblyName("testAssembly");
var assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.RunAndSave);
var moduleBuilder = assBuilder.DefineDynamicModule("dynamicModule", "dynamicBinder.dll");
var typeBuilder = moduleBuilder.DefineType(typeOfT.Name + "Proxy", TypeAttributes.Public | TypeAttributes.Class);
FieldBuilder bindingSourceField = typeBuilder.DefineField("BindingSource", typeOfT, FieldAttributes.Public);
foreach (FieldInfo toCopyField in typeOfT.GetFields())
{
PropertyBuilder propBuilder = typeBuilder.DefineProperty(toCopyField.Name, System.Reflection.PropertyAttributes.None, toCopyField.FieldType, null);
MethodBuilder getter = typeBuilder.DefineMethod("get_" + toCopyField.Name, MethodAttributes.Public, toCopyField.FieldType, Type.EmptyTypes);
ILGenerator getIL = getter.GetILGenerator();
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, bindingSourceField);
getIL.Emit(OpCodes.Ldfld, toCopyField);
getIL.Emit(OpCodes.Ret);
propBuilder.SetGetMethod(getter);
MethodBuilder setter = typeBuilder.DefineMethod("set_" + toCopyField.Name, MethodAttributes.Public, null, new Type[] { toCopyField.FieldType });
ILGenerator setIL = setter.GetILGenerator();
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldfld, bindingSourceField);
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Stfld, toCopyField);
setIL.Emit(OpCodes.Ret);
propBuilder.SetSetMethod(setter);
}
Type constructedType = typeBuilder.CreateType();
dynamic instance = Activator.CreateInstance(constructedType);
instance.BindingSource = toBind;
return instance;
}
}
所以这样做就是动态创建一个看起来像这样的新类型,你可以将它用作绑定源,作为控件和对象的间隔。
public class ComponentControlProxy
{
public ComponentControl<int> BindingSource;
public string A
{
get
{
return BindingSource.A;
}
set
{
BindingSource.A = value;
}
}
.. etc
}