This question(以及它的答案)解释了为什么你不能轻易地将DataGridView绑定到接口类型并获取从基接口继承的属性的列。
建议的解决方案是实现自定义TypeConverter。我的尝试如下。但是,创建绑定到ICamel的DataSource和DataGridView仍然只会生成一列(Humps)。我不认为我的转换器被.NET用来决定它可以为ICamel看到哪些属性。我做错了什么?
[TypeConverter(typeof(MyConverter))]
public interface IAnimal
{
string Name { get; set; }
int Legs { get; set; }
}
[TypeConverter(typeof(MyConverter))]
public interface ICamel : IAnimal
{
int Humps { get; set; }
}
public class MyConverter : TypeConverter
{
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
if(value is Type && (Type)value == typeof(ICamel))
{
List<PropertyDescriptor> propertyDescriptors = new List<PropertyDescriptor>();
foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(typeof(ICamel)))
{
propertyDescriptors.Add(pd);
}
foreach (PropertyDescriptor pd in TypeDescriptor.GetProperties(typeof(IAnimal)))
{
propertyDescriptors.Add(pd);
}
return new PropertyDescriptorCollection(propertyDescriptors.ToArray());
}
return base.GetProperties(context, value, attributes);
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
}
答案 0 :(得分:3)
DataGridView
不使用TypeConverter
; PropertyGrid
使用TypeConverter
。
如果它与DataGridView
之类的列表控件有关,那么另一个答案是错误的。
要在列表中提供自定义属性,您需要以下其中一项:
ITypedList
TypeDescriptionProvider
两者都是非平凡的。
答案 1 :(得分:1)
我的解决方法发生在dgv的绑定中。 我确实需要基本接口和继承接口保持在相同的结构中,因为我做其他事情宽度最终的concerete类,不仅显示DataGridView上的数据。所以,例如:
interface IGenericPerson
{
int ID { get; set; }
string Name { get; set; }
}
interface IOperator : IGenericPerson
{
bool IsAdmin { get; set; }
}
具体课程:
class Operator : IOperator
{
public Operator(){}
public Operator(int id, string name, bool isAdmin)
{
this.ID = id;
this.Name = name;
thsi.IsAdmin = isAdmin;
}
public int ID { get; set; }
public string name { get; set; }
public bool IsAdmin { get; set; }
}
并在网关类中:
public IList<IOperator> GetOperators()
{
IList<IOperator> list = new List<IOperator>();
list.add(new Operator(112, "Mark Twain", false);
list.add(new Operator(112, "Charles Manson", false);
list.add(new Operator(112, "Richard Nixon", true);
return list;
}
现在,如果我尝试绑定像这样的datagridView:
Gateway gt = new Gateway();
dgv.DataSource = gt.GetOperators();
我从IOperator接口获得了一个带有唯一bool IsAdmin列的DataGridView,而不是ID,也没有来自其基本接口的Name属性。
但如果我这样做:
Gateway gt = new Gateway();
IList<IOperator> list = gt.GetOperators();
IList<Operator> ds = new List<Operator>();
foreach(IOperator op in list)
ds.add((Operator)op);
dgv.DataSource = ds;
一切都以正确的方式运作。
通过这种方式,我不需要改变intarfaces链的结构,对其他目的很有用,只有qhen显示数据我只需插入上面的代码片段。
答案 2 :(得分:0)
我的建议是创建一个“重新实现”你想要的属性的接口:
假设您有两个界面:
public interface IHasName1
{
String Name1 { get; set; }
}
public interface IHasName2 : IHasName1
{
String Name2 { get; set; }
}
实现IHasName2的类:
public class HasTwoNames : IHasName2
{
#region IHasName1 Member
public string Name1 { get; set; }
#endregion
#region IHasName2 Member
public string Name2 {get; set; }
#endregion
}
现在,thx用于计算btw。,如果你有一个具有具体类型HasTwoNames的对象的List并且你将该列表绑定到dgv,它只显示IHasName2的成员(Name2)。
“解决方法”是创建一个新接口“IHasEverything”,它继承自IHasName2,因此从IHasName1继承并重新实现绑定中所需的Propertys(您可以使用新语句执行此操作
public interface IHasEverything : IHasName2
{
new String Name1 { get; set; }
new String Name2 { get; set; }
}
现在你的具体类“HasTwoNames”也需要实现IHasEverything:
public class HasTwoNames : IHasName2, IHasEverything
{
...
}
您可以将此List绑定到datagridview:
public List<IHasEverything> elements = new List<IHasEverything> {
new HasTwoNames { Name1 = "Name1", Name2 = "Name2"},
new HasTwoNames { Name1 = "Name3", Name2 = "Name4"},
};
我知道这只是一种解决方法,只有在您可以修改实现类的情况下才有可能。但它的确有效。 (如果从IHasName2中删除属性,代码仍会编译,但您会收到警告,IHasEverything不需要新关键字。