c# 4.0 - c# winforms应用程序中的datagridview / controls中的子级对象属性绑定
本文关键字:对象 属性 绑定 controls 应用程序 winforms datagridview | 更新日期: 2023-09-27 17:51:10
我被困在一个问题,而与绑定对象列表到datagridview或控件工作。实际上我想要的是,我有Person
, Address
和Contact
。Person
类有3个属性,一个是string类型的Name,一个是Address类型的Add
,最后一个是Contact
类型的Cont
。通过谷歌搜索,我发现我必须创建我创建的CustomTypeDescriptor
类,它只适用于Contact
或Address
的一个类。当我们输入两次时,它显示编译时错误,不能有重复的[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider<Contact>))]
。
我怎样才能解决这个问题?
在这里我提供的样本代码,我正试图实现,
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns.Add("Name", "Name");
dataGridView1.Columns.Add("City", "City");
dataGridView1.Columns.Add("ContactName", "ContactName");
dataGridView1.Columns["Name"].DataPropertyName = "Name";
dataGridView1.Columns["City"].DataPropertyName = "Add_City";
dataGridView1.Columns["ContactName"].DataPropertyName = "Cont_ContactName";
List<Person> PersonList = PersonProxy.GetPersonCollection();
dataGridView1.DataSource = PersonList;
}
}
public class PersonProxy
{
public static List<Person> GetPersonCollection()
{
List<Person> persList = new List<Person>();
persList.Add(new Person
{
Name = "Awadhendra",
Add = new Address
{
City = "Allahabad"
},
Cont = new Contact
{
ContactName = "Awadh"
}
});
persList.Add(new Person
{
Name = "Alok",
Add = new Address
{
City = "Allahabad"
},
Cont = new Contact
{
ContactName = "Alok"
}
});
persList.Add(new Person
{
Name = "Ankit",
Add = new Address
{
City = "Lucknow"
},
Cont = new Contact
{
ContactName = "Ankit"
}
});
persList.Add(new Person
{
Name = "Swati",
Add = new Address
{
City = "Lucknow"
},
Cont = new Contact
{
ContactName = "Awadh"
}
});
return persList;
}
}
[TypeDescriptionProvider(typeof(MyTypeDescriptionProvider<Contact>))]
public class Person
{
public string Name { get; set; }
public Address Add { get; set; } ////How to get address and contact both for binding.
public Contact Cont { get; set; } ////Write now am getting Contact
}
public class Address
{
public string City { get; set; }
}
public class Contact
{
public string ContactName { get; set; }
}
public class MyTypeDescriptionProvider<T> : TypeDescriptionProvider
{
private ICustomTypeDescriptor td;
public MyTypeDescriptionProvider()
: this(TypeDescriptor.GetProvider(typeof(Person)))
{
}
public MyTypeDescriptionProvider(TypeDescriptionProvider parent)
: base(parent)
{
}
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
if (td == null)
{
td = base.GetTypeDescriptor(objectType, instance);
td = new MyCustomTypeDescriptor(td, typeof(T));
}
return td;
}
}
public class SubPropertyDescriptor : PropertyDescriptor
{
private PropertyDescriptor _subPD;
private PropertyDescriptor _parentPD;
public SubPropertyDescriptor(PropertyDescriptor parentPD, PropertyDescriptor subPD, string pdname)
: base(pdname, null)
{
_subPD = subPD;
_parentPD = parentPD;
}
public override bool IsReadOnly { get { return false; } }
public override void ResetValue(object component) { }
public override bool CanResetValue(object component) { return false; }
public override bool ShouldSerializeValue(object component)
{
return true;
}
public override Type ComponentType
{
get { return _parentPD.ComponentType; }
}
public override Type PropertyType { get { return _subPD.PropertyType; } }
public override object GetValue(object component)
{
return _subPD.GetValue(_parentPD.GetValue(component));
}
public override void SetValue(object component, object value)
{
_subPD.SetValue(_parentPD.GetValue(component), value);
OnValueChanged(component, EventArgs.Empty);
}
}
public class MyCustomTypeDescriptor : CustomTypeDescriptor
{
Type typeProperty;
public MyCustomTypeDescriptor(ICustomTypeDescriptor parent, Type type)
: base(parent)
{
typeProperty = type;
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
PropertyDescriptorCollection cols = base.GetProperties(attributes);
string propertyName = "";
foreach (PropertyDescriptor col in cols)
{
if (col.PropertyType.Name == typeProperty.Name)
propertyName = col.Name;
}
PropertyDescriptor pd = cols[propertyName];
PropertyDescriptorCollection children = pd.GetChildProperties();
PropertyDescriptor[] array = new PropertyDescriptor[cols.Count + children.Count];
int count = cols.Count;
cols.CopyTo(array, 0);
foreach (PropertyDescriptor cpd in children)
{
array[count] = new SubPropertyDescriptor(pd, cpd, pd.Name + "_" + cpd.Name);
count++;
}
PropertyDescriptorCollection newcols = new PropertyDescriptorCollection(array);
return newcols;
}
}
谢谢,
基于MSDN
有两种方法可以将
TypeDescriptionProvider
和TypeDescriptor
关联起来:
- 在设计时,当目标类可以分配适当的
TypeDescriptionProviderAttribute
标签时。- 在运行时,当可以调用
TypeDescriptor
类的AddProvider
方法之一时。这些重载方法要么需要目标对象,要么需要它的类类型。
所以只要在运行时添加它们:
private void Form1_Load(object sender, EventArgs e)
{
dataGridView1.AutoGenerateColumns = false;
dataGridView1.Columns.Add("Name", "Name");
dataGridView1.Columns.Add("City", "City");
dataGridView1.Columns.Add("ContactName", "ContactName");
dataGridView1.Columns["Name"].DataPropertyName = "Name";
dataGridView1.Columns["City"].DataPropertyName = "Add_City";
dataGridView1.Columns["ContactName"].DataPropertyName = "Cont_ContactName";
List<Person> PersonList = PersonProxy.GetPersonCollection();
//add them here
System.ComponentModel.TypeDescriptor.AddProvider((new MyTypeDescriptionProvider<Address>()), typeof(Person));
System.ComponentModel.TypeDescriptor.AddProvider((new MyTypeDescriptionProvider<Contact>()), typeof(Person));
dataGridView1.DataSource = PersonList;
}
我发现在。net 4.5中,前面的答案几乎可以工作,但问题是AddProvider方法作为最后一个获胜,所以我们只能看到合同的属性,而不是地址。
解决方案是将提供商链接在一起,这样我们就可以得到…
//add them here
var addressProvider = new MyTypeDescriptionProvider<Address>();
System.ComponentModel.TypeDescriptor.AddProvider(t1, typeof(Person));
System.ComponentModel.TypeDescriptor.AddProvider(new MyTypeDescriptionProvider<Contact>(t1), typeof(Person));