Problem Statement
As simple as that, I have created a component that has a property whose data type is List (Of String). I want user to see this property value in Property Grid of Visual Studio, and when he clicks on the edit collection button, he should be able to add strings, which I can reflect back in the property. By default, Visual Studio provides a Collection Editor. This collection editor initializes an object for the type. As value types like String do not have a constructor, this editor does not work for them. So, task is to create an editor which can act as a default editor for value type collections.
Recommended Solutions
I searched a lot and found similar solutions for this problem. You can decorate your property with an EditorAttribute. Here you can refer to StringCollectionEditor provided in System.Design in the following way:
[Editor(@"System.Windows.Forms.Design.StringCollectionEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.Drawing.Design.UITypeEditor))] public List { get { return stringValues; } set { stringValues = value; } } |
But this did not worked out for me, as I could not get the values to persist when I entered them in the textbox. It is because StringCollectionEditor works well with string arrays or, specialized or string collections, but not so with List(Of T).
My Solution
Here is what I did and what you can do to create editor for any data type:
I created a custom form called StringCollectionForm.cs (just like the form shown above) and a custom editor class called StringCollectionEditor derived from UITypeEditor. To make that editor work, only one method called EditValue needs to be overridden. One of its parameters is an object that provides the value of collection. Initially this value is null. You can create any collection and return it as an object. Next time, you will receive the same object as parameter. So, you get complete control over the working of editor. I took values from the form’s textbox and added them to List(Of string). Next time, when I receive the object, I cast it back to List(Of string).
Only thing you need to make sure of is that object you are returning should be such that it can be cast to data type of the property. And you will receive the value of same data type.
Here is the C# code snippet for that:
public override object EditValue(ITypeDescriptorContext context, IServiceProvider serviceprovider, object value) { if (serviceprovider != null) { mapiEditorService = serviceprovider .GetService(typeof(IWindowsFormsEditorService)) as IWindowsFormsEditorService; } if (mapiEditorService != null) { StringCollectionForm form = new StringCollectionForm(); // Retrieve previous values entered in list. if (value != null) { List form.txtListValues.Text = String.Empty; foreach (string stringValue in stringList) { form.txtListValues.Text += stringValue + "\r\n"; } } // Show Dialog. form.ShowDialog(); if (form.DialogResult == DialogResult.OK) { List string[] listSeparator = new string[1]; listSeparator[0] = "\r\n"; string[] listValues = form.txtListValues.Text .Split(listSeparator, StringSplitOptions.RemoveEmptyEntries); // Add list values in list. foreach (string stringValue in listValues) { stringList.Add(stringValue); } value = stringList; } return value; } return null; } |
7 comments:
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
// Specify a modal UITypeEditor
return UITypeEditorEditStyle.Modal;
}
Oops, did not include explanation in the comment.
I also had to override the GetEditStyle method. Your post was helpfull. Thanks.
Thanks for writing this.
Hi,
This is great, although would you be able to post your entire source code, so as to get an idea of how everything fits together?
sorry, I guess I am more interested in how this persists in source mode? As an inner property? If so, how did u set this?
You might consider using the DesignerSerializationVisibility attribute, works fine for me.
private StringCollection strings = new StringCollection();
[Editor("System.Windows.Forms.Design.StringCollectionEditor,System.Design,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a",typeof(System.Drawing.Design.UITypeEditor))] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public StringCollection Strings
{
get { return column; }
set { column = value; }
}
Did you know that instead of doing:
form.txtListValues.Text += stringValue + "\r\n";
You could do form.txtListValues.Text += stringValue + Environment.NewLine;
Not that it matters much in windows, but is more future proof.
Post a Comment