我有一个包含动态属性的项目列表。
目标是让类具有已定义的属性,但也允许动态地为其实例设置新属性。一个示例是下面代码中的“MyDynamicObject”类。
然后将列表(下面代码中的'DynamicITypedList'实例)绑定到DataGridView,它将显示列表项的每个属性并将其绑定到列。
我面临的问题是:只要我使'DynamicITypedList'类实现'ITypedList',DataGridView中的所有行都会显示列表中第一项的属性!
如果我不这样做使列表类实现'ITypedList'(在下面的代码的最后注释掉'ITypedList'),不显示动态添加的属性值(因为没有调用特定的GetItemProperties()),但所有行都显示在DataGridView ......
请你帮我解决一下?
这是调用代码,准备在包含一个“datagridView1”控件的WinForm中运行:
using System;
using System.Collections.Generic;
using System.Windows.Forms;
namespace Tests
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonITypedList_Click(object sender, EventArgs e)
{
MyDynamicObject myDynamicObject1 = new MyDynamicObject();
myDynamicObject1.Id = 1;
myDynamicObject1.AsDynamic.NewProperty = "NEWPROP1";
MyDynamicObject myDynamicObject2 = new MyDynamicObject();
myDynamicObject2.Id = 2;
DynamicITypedList<MyDynamicObject> myDynamicObjectDynamicITypedList = new DynamicITypedList<MyDynamicObject>();
myDynamicObjectDynamicITypedList.Add(myDynamicObject1);
myDynamicObjectDynamicITypedList.Add(myDynamicObject2);
dataGridView1.AutoGenerateColumns = false;
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = myDynamicObjectDynamicITypedList;
bindingSource.AllowNew = true;
dataGridView1.DataSource = bindingSource;
foreach (KeyValuePair<string, object> property in myDynamicObject1.Data.Properties)
{
DataGridViewTextBoxColumn dynamicPropertyColumn = new DataGridViewTextBoxColumn();
dynamicPropertyColumn.DataPropertyName = property.Key;
dynamicPropertyColumn.HeaderText = property.Key;
dynamicPropertyColumn.Name = property.Key;
dataGridView1.Columns.Add(dynamicPropertyColumn);
}
}
}
}
以下是课程:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Dynamic;
using System.Linq;
using System.Reflection;
namespace Tests
{
public interface IMyDynamic
{
MyDynamic Data { get; set; }
IEnumerable<string> GetDynamicMemberNames();
}
public class MyDynamic : DynamicObject, IDynamicMetaObjectProvider
{
object Instance { get; set; }
Type InstanceType { get; set; }
Dictionary<string, MemberInfo> MemberInfos { get; set; }
PropertyInfo[] instancePropertyInfo;
PropertyInfo[] InstancePropertyInfo
{
get
{
if (instancePropertyInfo == null && Instance != null)
instancePropertyInfo = Instance.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
return instancePropertyInfo;
}
}
public MyDynamic()
{
Initialize(this);
}
public MyDynamic(object instance)
{
Initialize(instance);
}
public IEnumerable<KeyValuePair<string, object>> GetProperties(bool includeInstanceProperties = false)
{
if (includeInstanceProperties && Instance != null)
{
foreach (var prop in this.InstancePropertyInfo)
yield return new KeyValuePair<string, object>(prop.Name, prop.GetValue(Instance, null));
}
foreach (var key in this.Properties.Keys)
yield return new KeyValuePair<string, object>(key, this.Properties[key]);
}
public override IEnumerable<string> GetDynamicMemberNames()
{
foreach (var prop in GetProperties(true))
yield return prop.Key;
}
public Dictionary<string, object> Properties { get; private set; }
public object this[string key]
{
get
{
try
{
//Try to get from properties collection first
return Properties[key];
}
catch (KeyNotFoundException)
{
//Try reflection on instanceType
object result = null;
if (GetProperty(Instance, key, out result))
return result;
//Nope doesn't exist
//throw; //Preserve the stack trace
return null;
}
}
set
{
if (Properties.ContainsKey(key))
{
Properties[key] = value;
return;
}
//Check instance for existance of type first
var miArray = InstanceType.GetMember(key, BindingFlags.Public | BindingFlags.GetProperty);
if (miArray != null && miArray.Length > 0)
SetProperty(Instance, key, value);
else
Properties[key] = value;
}
}
protected virtual void Initialize(object instance)
{
Instance = instance;
if (instance != null)
InstanceType = instance.GetType();
Properties = new Dictionary<string, object>();
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = null;
//First check the Properties collection for member
if (Properties.Keys.Contains(binder.Name))
{
result = Properties[binder.Name];
return true;
}
//Next check for Public properties via Reflection
if (Instance != null)
{
try
{
return GetProperty(Instance, binder.Name, out result);
}
catch { }
}
//Failed to retrieve a property
result = null;
return false;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
//First check to see if there's a native property to set
if (Instance != null)
{
try
{
if (SetProperty(Instance, binder.Name, value))
return true;
}
catch { }
}
//No match - set or add to dictionary
Properties[binder.Name] = value;
return true;
}
protected bool GetProperty(object instance, string name, out object result)
{
if (instance == null)
instance = this;
if (MemberInfos == null)
{
MemberInfos = new Dictionary<string, MemberInfo>();
MemberInfo[] memberInfos = InstanceType.GetMember(name, BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance);
foreach (MemberInfo instanceMemberInfo in InstanceType.GetMembers())
MemberInfos.Add(instanceMemberInfo.Name, instanceMemberInfo);
}
result = null;
MemberInfo propertyMemberInfo;
if (!MemberInfos.TryGetValue(name, out propertyMemberInfo))
return false;
if (propertyMemberInfo.MemberType == MemberTypes.Property)
{
result = ((PropertyInfo)propertyMemberInfo).GetValue(instance, null);
return true;
}
return false;
}
protected bool SetProperty(object instance, string name, object value)
{
if (instance == null)
instance = this;
if (MemberInfos == null)
{
MemberInfos = new Dictionary<string, MemberInfo>();
MemberInfo[] memberInfos = InstanceType.GetMember(name, BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance);
foreach (MemberInfo instanceMemberInfo in InstanceType.GetMembers())
MemberInfos.Add(instanceMemberInfo.Name, instanceMemberInfo);
}
MemberInfo propertyMemberInfo;
if (!MemberInfos.TryGetValue(name, out propertyMemberInfo))
return false;
if (propertyMemberInfo.MemberType == MemberTypes.Property)
{
((PropertyInfo)propertyMemberInfo).SetValue(Instance, value, null);
return true;
}
return false;
}
}
public /*abstract*/ class MyDynamicObject : MyDynamic, IMyDynamic
{
public MyDynamic Data
{
get { return data; }
set { data = dynamicData = value; }
}
public dynamic AsDynamic
{
get { return dynamicData; }
}
public Int64 Id { get { return AsDynamic.Id; } set { AsDynamic.Id = value; } }
MyDynamic data;
dynamic dynamicData;
public MyDynamicObject() : this(new MyDynamic())
{ }
public MyDynamicObject(MyDynamic data)
{
Data = data;
TypeDescriptor.AddProvider(new MyDynamicTypeDescriptionProvider(), this); //Data);
}
}
public class IMyDynamicTypeDescriptor : ICustomTypeDescriptor
{
private readonly IMyDynamic m_Instance;
public IMyDynamicTypeDescriptor(object instance)
{
if (instance is MyDynamicObject)
m_Instance = (MyDynamicObject)instance;
else if (instance is IMyDynamic)
m_Instance = (IMyDynamic)instance;
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return m_Instance;
}
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return null;
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
return new PropertyDescriptorCollection(
m_Instance.Data.Properties.Keys
.Select(x => new MyDynamicPropertyDescriptor(m_Instance, x))
.ToArray<PropertyDescriptor>());
}
}
public class MyDynamicPropertyDescriptor : PropertyDescriptor
{
private readonly IMyDynamic m_Instance;
private readonly string m_Name;
public MyDynamicPropertyDescriptor(IMyDynamic instance, string name)
: base(name, null)
{
m_Instance = instance;
m_Name = name;
}
public override Type PropertyType
{
get
{
if (m_Instance.Data[m_Name] != null)
return m_Instance.Data[m_Name].GetType();
else
{
//...
return typeof(string);
}
}
}
public override void SetValue(object component, object value)
{
m_Instance.Data[m_Name] = value;
}
public override object GetValue(object component)
{
return m_Instance.Data[m_Name];
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type ComponentType
{
get { return null; }
}
public override bool CanResetValue(object component)
{
return false;
}
public override void ResetValue(object component)
{ }
public override bool ShouldSerializeValue(object component)
{
return false;
}
public override string Category
{
get { return string.Empty; }
}
public override string Description
{
get { return string.Empty; }
}
}
public class MyDynamicTypeDescriptionProvider : TypeDescriptionProvider
{
private static readonly TypeDescriptionProvider m_Default = TypeDescriptor.GetProvider(typeof(ExpandoObject));
public MyDynamicTypeDescriptionProvider() : base(m_Default)
{ }
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
var defaultDescriptor = base.GetTypeDescriptor(objectType, instance);
return (instance == null ? defaultDescriptor : new IMyDynamicTypeDescriptor(instance));
}
}
public class DynamicITypedList<T> : ObservableCollection<T>, /*List<T>, IList<T>,*/ ITypedList where T : IMyDynamic, new()
{
public string GetListName(PropertyDescriptor[] listAccessors)
{
return null;
}
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
return TypeDescriptor.GetProperties(this.FirstOrDefault());
}
}
}
答案 0 :(得分:-1)
这不是直接回答问题的答案,而是......
前几天我完成了同样的任务。将动态对象绑定到数据网格。
我的解决方案是:
请务必按照正确的顺序执行所有操作,因为如果您不这样做,您的动态属性对于grid / bindingsource是未知的,因此无法显示。
我不记得所有这些的确切顺序,也许你应该尝试一下我的提示并回来再询问一下?