How can I use a WinForms PropertyGrid to edit a list of strings?
In my application I have a property grid to allow users to change settings. This works fine for strings and other value properties, but what I need now is a list of strings that can be edited by users.
The problem is that if I have MyPropertyGrid.SelectedObject = new { Test = new List<string>() };
in my code and the user attempts to edit the Test
property, when they click on the Add button, the following error occurs:
Constructor on type 'System.String' not found
This makes sense as string开发者_JAVA技巧s are immutable. However, I still need some way to store multiple strings (or string-like data) in a property grid.
Does anyone have any ideas on how I can accomplish this?
Yes, you can specify an System.ComponentModel.Editor
attribute on your list of strings, with StringCollectionEditor
as the editor. You need to add a reference to System.Design.Dll to your project, in order for this to compile.
Example, suppose your object is like this:
[DefaultProperty("Name")]
public class CustomObject
{
[Description("Name of the thing")]
public String Name { get; set; }
[Description("Whether activated or not")]
public bool Activated { get; set; }
[Description("Rank of the thing")]
public int Rank { get; set; }
[Description("whether to persist the settings...")]
public bool Ephemeral { get; set; }
[Description("extra free-form attributes on this thing.")]
[Editor(@"System.Windows.Forms.Design.StringCollectionEditor," +
"System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
typeof(System.Drawing.Design.UITypeEditor))]
[TypeConverter(typeof(CsvConverter))]
public List<String> ExtraStuff
{
get
{
if (_attributes == null)
_attributes = new List<String>();
return _attributes;
}
}
private List<String> _attributes;
}
The property grid for that looks like this:
Click on the ...
and you get:
If you don't like the builtin collection editor, you can implement your own custom collection editor.
My example shows the use of a TypeConverter attribute. If you don't do that, then the list displays in the prop grid as "(Collection)". The TypeConverter gets it to display as something intelligent. For example, to display a short string representation of the collection in the property grid, like this:
...the TypeConverter is like this:
public class CsvConverter : TypeConverter
{
// Overrides the ConvertTo method of TypeConverter.
public override object ConvertTo(ITypeDescriptorContext context,
CultureInfo culture, object value, Type destinationType)
{
List<String> v = value as List<String>;
if (destinationType == typeof(string))
{
return String.Join(",", v.ToArray());
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
You don't need a setter on the List<String>
, because the collection editor doesn't set that property, it merely adds or removes entries to the property. So just provide the getter.
If you just need a string container just use: BindingList<string>
instead of list<string>
The editor is created automatically.
Also, "casting" back and forth to List<T>
is easy.
From List to BindingList just use the bList = BindingList(orignalList)
constructor (if you get read only error - insert the list one by one). and to get the list you can use the .ToList()
extension method.
Property declaration misses one important attribute:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
Without it designer does not serialize collection data.
精彩评论