PropertyGrid默认情况下可以显示和修改List<string>类型的属性,但不支持List<class>类型。不过你可以通过自定义TypeConverter来扩展PropertyGrid的功能,使其支持显示和修改List<class>类型的属性。
以下是一个简单的示例:
public class MyListTypeConverter : TypeConverter
{
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
return true;
}
public override PropertyDescriptorCollection GetProperties(
ITypeDescriptorContext context,
object value,
Attribute[] attributes)
{
var properties = new List<PropertyDescriptor>();
if (value is List<string> stringList)
{
for (int i = 0; i < stringList.Count; i++)
{
properties.Add(new StringListPropertyDescriptor(stringList, i));
}
}
else if (value is List<MyClass> myClassList)
{
for (int i = 0; i < myClassList.Count; i++)
{
properties.Add(new MyClassListPropertyDescriptor(myClassList, i));
}
}
return new PropertyDescriptorCollection(properties.ToArray());
}
}
public class StringListPropertyDescriptor : PropertyDescriptor
{
private readonly List<string> _list;
private readonly int _index;
public StringListPropertyDescriptor(List<string> list, int index)
: base("Item " + index, null)
{
_list = list;
_index = index;
}
public override Type ComponentType => typeof(List<string>);
public override bool IsReadOnly => false;
public override Type PropertyType => typeof(string);
public override object GetValue(object component)
{
return _list[_index];
}
public override void SetValue(object component, object value)
{
_list[_index] = (string)value;
}
}
public class MyClassListPropertyDescriptor : PropertyDescriptor
{
private readonly List<MyClass> _list;
private readonly int _index;
public MyClassListPropertyDescriptor(List<MyClass> list, int index)
: base("Item " + index, null)
{
_list = list;
_index = index;
}
public override Type ComponentType => typeof(List<MyClass>);
public override bool IsReadOnly => false;
public override Type PropertyType => typeof(MyClass);
public override object GetValue(object component)
{
return _list[_index];
}
public override void SetValue(object component, object value)
{
_list[_index] = (MyClass)value;
}
public override PropertyDescriptorCollection GetChildProperties(
object instance,
Attribute[] attributes)
{
var properties = TypeDescriptor.GetProperties(instance, attributes)
.Cast<PropertyDescriptor>();
return new PropertyDescriptorCollection(properties.ToArray());
}
}
public class MyClass
{
public string StringProperty { get; set; }
public int IntProperty { get; set; }
}
public class MyViewModel
{
[TypeConverter(typeof(MyListTypeConverter))]
public List<string> StringList { get; set; }
[TypeConverter(typeof(MyListTypeConverter))]
public List<MyClass> MyClassList { get; set; }
}
在这个示例中,我们定义了两个自定义的PropertyDescriptor分别用于表示List<string>和List<MyClass>类型的属性。我们还定义了一个自定义的TypeConverter,用于选择哪种PropertyDescriptor应该用于特定的属性。
在MyClassListPropertyDescriptor中,我们还需要重写GetChildProperties
方法,以便能够获取MyClass类型的属性。
最后,将MyViewModel对象作为PropertyGrid的SelectedObject即可:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MyViewModel
{
StringList = new List<string> { "foo", "bar" },
MyClassList = new List<MyClass>
{
new MyClass { StringProperty = "hello", IntProperty = 42 },
new MyClass { StringProperty = "world", IntProperty = 123 }
}
};
}
}