Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# DataGridView不显示实现ICustomTypeDescriptor的对象的属性_C#_Winforms_Datagridview_Icustomtypedescriptor - Fatal编程技术网

C# DataGridView不显示实现ICustomTypeDescriptor的对象的属性

C# DataGridView不显示实现ICustomTypeDescriptor的对象的属性,c#,winforms,datagridview,icustomtypedescriptor,C#,Winforms,Datagridview,Icustomtypedescriptor,我正在DataGridView中显示对象列表。一切正常。列根据对象的属性自动添加到DataGridView 现在,我更改了在网格中显示的类,以实现ICustomTypeDescriptor。但现在,当我将网格的数据源设置为自定义对象的列表时,网格不再显示任何列或行 我猜这与以下事实有关:使用ICustomTypeDescriptor,每个网格的每一行中显示的每个实例都可能返回一组不同的属性 我正在实现ICustomTypeDescriptor,以便允许用户在运行时向对象动态添加自定义属性。这些自

我正在DataGridView中显示对象列表。一切正常。列根据对象的属性自动添加到DataGridView

现在,我更改了在网格中显示的类,以实现ICustomTypeDescriptor。但现在,当我将网格的数据源设置为自定义对象的列表时,网格不再显示任何列或行

我猜这与以下事实有关:使用ICustomTypeDescriptor,每个网格的每一行中显示的每个实例都可能返回一组不同的属性

我正在实现ICustomTypeDescriptor,以便允许用户在运行时向对象动态添加自定义属性。这些自定义属性应通过DataGridView可见和可编辑

为什么DataGridView看不到我的ICustomTypeDescriptor方法?有没有其他方法可以动态地向DataGridView中显示的对象添加属性?

DataGridView查看元数据的列表版本;这方面的规则是。。。复杂:

如果数据源实现了IListSource,则计算GetList并将其用作数据源continue at 2 如果数据源实现ITypedList,则使用GetProperties获取元数据出口 如果可以找到一个类型化的非对象索引器,即public T this[int index],则T通过TypeDescriptor.GetPropertiestype用作源: 如果分配了TypeDescriptionProvider,则this用于针对类型出口的元数据 否则,反射将用于元数据退出 如果列表非空,则第一个对象通过TypeDescriptor用于元数据。GetPropertieslist[0]: 如果实现了ICustomTypeDescriptor,则使用它退出[*] 如果分配了TypeDescriptionProvider,则this用于针对类型exit[*]的元数据 否则将使用反射退出 否则元数据不可用,请退出 [*]=我不记得这两个人走哪条路了

如果您使用的是List或类似工具,那么您将遇到最简单的IMO案例-3。如果要提供自定义元数据,则;您最好编写一个TypeDescriptionProvider并将其与类型关联。我可以写一个例子,但在火车上要花一段时间,可能

编辑:使用ITypedList的示例;我将尝试调整它,改为使用TypeDescriptionProvider

第二次编辑:下面是一个使用TypeDescriptionProvider的完整但最小的示例;长代码警告

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
// example
static class Program {
    [STAThread]
    static void Main() { 
        PropertyBag.AddProperty("UserName", typeof(string), new DisplayNameAttribute("User Name"));
        PropertyBag.AddProperty("DateOfBirth", typeof(DateTime), new DisplayNameAttribute("Date of Birth"));
        BindingList<PropertyBag> list = new BindingList<PropertyBag>() {
            new PropertyBag().With("UserName", "Fred").With("DateOfBirth", new DateTime(1998,12,1)),
            new PropertyBag().With("UserName", "William").With("DateOfBirth", new DateTime(1997,4,23))
        };

        Application.Run(new Form {
            Controls = {
                new DataGridView { // prove it works for complex bindings
                    Dock = DockStyle.Fill,
                    DataSource = list,
                    ReadOnly = false, AllowUserToAddRows = true
                }
            },
            DataBindings = {
                {"Text", list, "UserName"} // prove it works for simple bindings
            }
        });
    }
}
// PropertyBag file 1; the core bag
partial class PropertyBag : INotifyPropertyChanged {
    private static PropertyDescriptorCollection props;
    public event PropertyChangedEventHandler PropertyChanged;
    void OnPropertyChanged(string propertyName) {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
    static PropertyBag() {
        props = new PropertyDescriptorCollection(new PropertyDescriptor[0], true);
        // init the provider; I'm avoiding TypeDescriptionProviderAttribute so that we
        // can exploit the default implementation for fun and profit
        TypeDescriptionProvider defaultProvider = TypeDescriptor.GetProvider(typeof(PropertyBag)),
            customProvider = new PropertyBagTypeDescriptionProvider(defaultProvider);
        TypeDescriptor.AddProvider(customProvider, typeof(PropertyBag));
    }
    private static readonly object syncLock = new object();
    public static void AddProperty(string name, Type type, params Attribute[] attributes) {
        lock (syncLock)
        {   // append the new prop, into a *new* collection, so that downstream
            // callers don't have to worry about the complexities
            PropertyDescriptor[] newProps = new PropertyDescriptor[props.Count + 1];
            props.CopyTo(newProps, 0);
            newProps[newProps.Length - 1] = new PropertyBagPropertyDescriptor(name, type, attributes);
            props = new PropertyDescriptorCollection(newProps, true);
        }
    }
    private readonly Dictionary<string, object> values;
    public PropertyBag()
    { // mainly want to enforce that we have a public parameterless ctor
        values = new Dictionary<string, object>();
    }    
    public object this[string key] {
        get {
            if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
            object value;
            values.TryGetValue(key, out value);
            return value;
        }
        set {
            if (string.IsNullOrEmpty(key)) throw new ArgumentNullException("key");
            var prop = props[key];
            if (prop == null) throw new ArgumentException("Invalid property: " + key, "key");
            values[key] = value;
            OnPropertyChanged(key);
        }
    }
    internal void Reset(string key) {
        values.Remove(key);
    }
    internal bool ShouldSerialize(string key) {
        return values.ContainsKey(key);
    }
}

static class PropertyBagExt
{
    // cheeky fluent API to make the example code easier:
    public static PropertyBag With(this PropertyBag obj, string name, object value) {
        obj[name] = value;
        return obj;
    }
}

// PropertyBag file 2: provider / type-descriptor
partial class PropertyBag {
    class PropertyBagTypeDescriptionProvider : TypeDescriptionProvider, ICustomTypeDescriptor {
        readonly ICustomTypeDescriptor defaultDescriptor;
        public PropertyBagTypeDescriptionProvider(TypeDescriptionProvider parent) : base(parent) {
            this.defaultDescriptor = parent.GetTypeDescriptor(typeof(PropertyBag));
        }
        public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) {
            return this;
        }
        AttributeCollection ICustomTypeDescriptor.GetAttributes() {
            return defaultDescriptor.GetAttributes();
        }
        string ICustomTypeDescriptor.GetClassName() {
            return defaultDescriptor.GetClassName();
        }
        string ICustomTypeDescriptor.GetComponentName() {
            return defaultDescriptor.GetComponentName();
        }
        TypeConverter ICustomTypeDescriptor.GetConverter() {
            return defaultDescriptor.GetConverter();
        }
        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() {
            return defaultDescriptor.GetDefaultEvent();
        }
        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() {
            return defaultDescriptor.GetDefaultProperty();
        }
        object ICustomTypeDescriptor.GetEditor(Type editorBaseType) {
            return defaultDescriptor.GetEditor(editorBaseType);
        }
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) {
            return defaultDescriptor.GetEvents(attributes);
        }
        EventDescriptorCollection ICustomTypeDescriptor.GetEvents() {
            return defaultDescriptor.GetEvents();
        }
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) {
            return PropertyBag.props; // should really be filtered, but meh!
        }
        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() {
            return PropertyBag.props;
        }
        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) {
            return defaultDescriptor.GetPropertyOwner(pd);
        }
    }
}
// PropertyBag file 3: property descriptor
partial class PropertyBag {
    class PropertyBagPropertyDescriptor : PropertyDescriptor {
        private readonly Type type;
        public PropertyBagPropertyDescriptor(string name, Type type, Attribute[] attributes)
            : base(name, attributes) {
            this.type = type;
        }
        public override object GetValue(object component) {
            return ((PropertyBag)component)[Name];
        }
        public override void SetValue(object component, object value) {
            ((PropertyBag)component)[Name] = value;
        }
        public override void ResetValue(object component) {
            ((PropertyBag)component).Reset(Name);
        }
        public override bool CanResetValue(object component) {
            return true;
        }
        public override bool ShouldSerializeValue(object component) {
            return ((PropertyBag)component).ShouldSerialize(Name);
        }
        public override Type PropertyType {
            get { return type; }
        }
        public override bool IsReadOnly {
            get { return false; }
        }
        public override Type ComponentType {
            get { return typeof(PropertyBag); }
        }
    }
}