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