首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对象上的ICustomTypeDescriptor包装器

对象上的ICustomTypeDescriptor包装器
EN

Stack Overflow用户
提问于 2012-02-24 08:28:26
回答 2查看 2.7K关注 0票数 3

我在应用程序中实现了ICustomTypeDescriptor,以便能够在运行时定义自定义属性。我的基本实现如下:

代码语言:javascript
复制
public class DynamicClass <T> : ICustomTypeDescriptor
{
    private readonly T _object;

    public DynamicClass(T trackedObject)
    {
        _object = trackedObject;
    }

    // Collection to code add dynamic properties
    public KeyedCollection<string, DynamicProperty> Properties
    {
        get;
        private set;
    }

    // ICustomTypeDescriptor implementation
    public AttributeCollection GetAttributes()
    {
        return TypeDescriptor.GetAttributes(_object, true);
    }

    public string GetClassName()
    {
        return TypeDescriptor.GetClassName(_object, true);
    }

    public string GetComponentName()
    {
        return TypeDescriptor.GetComponentName(_object, true);
    }

    public TypeConverter GetConverter()
    {
        return TypeDescriptor.GetConverter(_object, true);
    }

    public EventDescriptor GetDefaultEvent()
    {
        return TypeDescriptor.GetDefaultEvent(_object, true);
    }

    public PropertyDescriptor GetDefaultProperty()
    {
        return TypeDescriptor.GetDefaultProperty(_object, true);
    }

    public object GetEditor(Type editorBaseType)
    {
        throw new NotImplementedException();
    }

    public EventDescriptorCollection GetEvents()
    {
        return TypeDescriptor.GetEvents(_object, true);
    }

    public EventDescriptorCollection GetEvents(Attribute[] attributes)
    {
        return TypeDescriptor.GetEvents(_object, attributes, true);
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        return TypeDescriptor.GetProperties(_object, true);
    }

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        return TypeDescriptor.GetProperties(_object, attributes, true);
    }

    public object GetPropertyOwner(PropertyDescriptor pd)
    {
        return _object;
    }
}

问题是,现在当我使用DynamicClass绑定将对象绑定到文本框时,它不再工作了。

我就是这样用的:

代码语言:javascript
复制
 DynamicClass<ExtensionModel> binder = new DynamicClass<ExtensionModel>(ext);
 _versionLabel.DataBindings.Add("Text", binder, "SelectedVersion", false, DataSourceUpdateMode.OnPropertyChanged);

我得到了一个例外:“Object与目标类型不匹配。”

对象与目标类型不匹配。

(在System.Reflection.RuntimeMethodInfo.CheckConsistency(Object目标)在System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,binder粘合剂,Object[]参数,CultureInfo文化,布尔skipVisibilityChecks)在System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,binder粘合剂,Object[]参数,CultureInfo培养)

在System.ComponentModel.ReflectEventDescriptor.AddEventHandler(Object组件上,代表值在System.ComponentModel.ReflectPropertyDescriptor.AddValueChanged(Object组件上,EventHandler处理程序在System.Windows.Forms.BindToObject.CheckBinding() at System.Windows.Forms.Binding.SetListManager(BindingManagerBase bindingManagerBase(在System.Windows.Forms.ListManagerBindingsCollection.AddCore(Binding dataBinding)在System.Windows.Forms.BindingsCollection.Add(Binding绑定时)在System.Windows.Forms.BindingContext.UpdateBinding(BindingContext newBindingContext,绑定)在System.Windows.Forms.Control.UpdateBindings()

如果我使用ext对象而不是绑定器,则绑定可以工作。我在ICustomTypeDescriptor实现中遗漏了什么吗?

EN

回答 2

Stack Overflow用户

发布于 2013-12-25 18:27:59

您必须用自定义描述符包装原始描述符。以下是代码:

代码语言:javascript
复制
#region IBindingProxy

public interface IBindingProxy
{
    void CheckAndNotify();
}

#endregion

public class BindingProxy : CustomTypeDescriptor, INotifyPropertyChanged, IBindingProxy
{
    #region Static Constructor

    private static readonly IDictionary<Type, PropertyDescriptorCollection> propertyCache;

    static BindingProxy()
    {
        propertyCache = new Dictionary<Type, PropertyDescriptorCollection>();
    }

    private static PropertyDescriptorCollection GetTypeProperties(Type type)
    {
        lock (propertyCache)
        {
            PropertyDescriptorCollection properties;
            if (!propertyCache.TryGetValue(type, out properties))
            {
                var list = new List<PropertyDescriptor>();
                GetTypeProperties(list, type);
                properties = new PropertyDescriptorCollection(list.ToArray());
                propertyCache.Add(type, properties);
            }
            return properties;
        }
    }

    private static void GetTypeProperties(ICollection<PropertyDescriptor> list, Type type)
    {
        foreach (var @interface in type.GetInterfaces())
        {
            GetTypeProperties(list, @interface);
        }
        foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(type))
        {
            list.Add(new ProxyPropertyDescriptor(property));
        }
    }

    #endregion

    private readonly PropertyDescriptorCollection properties;
    private readonly object instance;

    public event PropertyChangedEventHandler PropertyChanged;

    public BindingProxy(object instance)
    {
        this.instance = instance;

        properties = instance == null
            ? PropertyDescriptorCollection .Empty
            : GetTypeProperties(instance.GetType());
    }

    public void CheckAndNotify()
    {
        OnPropertyChanged(null);
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public object Instance
    {
        get { return instance; }
    }

    public override PropertyDescriptorCollection GetProperties()
    {
        return GetProperties(null);
    }

    public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
    {
        return properties;
    }

    public override Object GetPropertyOwner(PropertyDescriptor property)
    {
        return this;
    }

    #region ProxyPropertyDescriptor

    private class ProxyPropertyDescriptor : PropertyDescriptor
    {
        private readonly PropertyDescriptor property;

        public ProxyPropertyDescriptor(PropertyDescriptor property) : base(property)
        {
            this.property = property;
        }

        //public override string DisplayName
        //{
        //    get { return property.DisplayName; }
        //}

        //public override string Description
        //{
        //    get { return property.Description; }
        //}

        //public override string Category
        //{
        //    get { return property.Category; }
        //}

        //public override TypeConverter Converter
        //{
        //    get { return converter; }
        //}

        public override bool IsReadOnly
        {
            get { return property.IsReadOnly; }
        }

        public override void ResetValue(object component)
        {
        }

        public override bool CanResetValue(object component)
        {
            return false;
        }

        public override bool ShouldSerializeValue(object component)
        {
            return false;
        }

        public override Type ComponentType
        {
            get { return property.ComponentType; }
        }

        public override Type PropertyType
        {
            get { return property.PropertyType; }
        }

        public override object GetValue(object component)
        {
            return property.GetValue(((BindingProxy)component).instance);
        }

        public override void SetValue(object component, object value)
        {
            var instance = ((BindingProxy)component).instance;
            property.SetValue(instance, value);
            OnValueChanged(instance, EventArgs.Empty);
        }
    }

    #endregion
}
票数 1
EN

Stack Overflow用户

发布于 2012-06-09 09:36:13

我已经在我的测试代码中复制了您的问题。我可以看到,如果您不在INotifyPropertyChanged上实现ExtensionModel,那么它就能工作!

因此,ICustomTypeDescriptor的实现有一些不适用于实现INotifyPropertyChanged的属性类的东西。

这是可行的,但是如果取消对INotifyPropertyChange的注释,它就会崩溃。

代码语言:javascript
复制
public class BindingExample
{
    public void Shows_Binding_To_A_Label_With_DynamicClass()
    {
        Form frm = new Form();
        Label _versionLabel = new Label();
        frm.Controls.Add(_versionLabel);

        ExtensionModel ext = new ExtensionModel() { SelectedVersion = "DynamicClass Example" };
        DynamicClass<ExtensionModel> binder = new DynamicClass<ExtensionModel>(ext);

        _versionLabel.DataBindings.Add("Text", binder, "SelectedVersion", false, DataSourceUpdateMode.OnPropertyChanged);

        frm.ShowDialog();
    }
}

public class ExtensionModel// : INotifyPropertyChanged
{
    string selectedVersion;
    public string SelectedVersion
    {
        get { return selectedVersion; }
        set
        {
            selectedVersion = value;
            onPropertyChanged("SelectedVersion");
        }
    }

    void onPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

我想让这一切顺利进行,所以我会继续玩下去。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9427587

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档