简体   繁体   English

C#通用类型; 无法绑定到属性或列

[英]C# Generic type; Cannot bind to the property or column

So I have this Generic typed class that uses System.Reflection to get all public variables from a Class and render those as Controls. 因此,我有一个泛型类型的类,该类使用System.Reflection从类中获取所有公共变量并将其呈现为控件。

However I need to be able to use these variables as DataBindings for the Controls so when the controls receive input, that input saves to the corresponding variables. 但是,我需要能够将这些变量用作控件的DataBindings,以便在控件接收输入时,该输入将保存到相应的变量中。

This is what I have so far but I'm getting a 'Cannot bind to the property or column' error. 这是我到目前为止,但我得到一个'无法绑定到属性或列'错误。

The Class: 班级:

public class ComponentControl<T> where T : Component
{
   private T component;

   public ComponentControl(T component)
   {
      this.component = component;
   }
}

The part that wont work: 不起作用的部分:

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);
}

I think you can only bind to properties of a custom object, not fields. 我认为您只能绑定到自定义对象的属性,而不能绑定到字段。 This seems a bit overkill but if there's an easier way I'm sure someone will correct me.. 这似乎有点矫kill过正,但是如果有更简单的方法,我敢肯定有人会纠正我的。

Assuming you don't want to change your fields to properties, and you really want to use binding, you could generate a kind of DTO to bind to instead. 假设您不想将字段更改为属性,并且您确实想要使用绑定,则可以生成一种要绑定的DTO。 For example, here is how you would bind, so use proxyType instead of your actual type. 例如,这是绑定的方式,因此请使用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);
}

And here is the code for DynamicProxyGenerator which generates that.. 这里是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;
    }
}  

So what this does is create a new type on the fly that would look like this, which you can use as the binding source to act as a go between for the control and your object. 所以这样做就是在运行中创建一个看起来像这样的新类型,您可以将其用作绑定源,作为控件和对象之间的转换。

public class ComponentControlProxy
{
    public ComponentControl<int> BindingSource;

    public string A 
    {
        get 
        {
            return BindingSource.A;
        }
        set 
        {
            BindingSource.A = value;
        }
    }

    .. etc
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM