I'm trying to make a WinForms usercontrol with a Collection<T>
as a property (Where T stands for some custom classes). I already read a lot about this topic, however I can't let this work properly at design time (at runtime everything works fine). To be more precise: the collection editor shows fine when I click on the "..." button in the property window and I can add and delete items. But when I click the OK button nothing happens and when I reopen the collection editor, all items are lost. When I take a look at the designer file, I see my property is assigned to null, instead of the composed collection. I'll show you the most important code:
UserControl:
[Browsable(true),
Description("The different steps displayed in the control."),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Editor(typeof(CustomCollectionEditor), typeof(UITypeEditor))]
public StepCollection Steps
{
get
{
return wizardSteps;
}
set
{
wizardSteps = value;
UpdateView(true);
}
}
StepCollection class:
public class StepCollection : System.Collections.CollectionBase
{
public StepCollection() : base() { }
public void Add(Step item) { List.Add(item); }
public void Remove(int index) { List.RemoveAt(index); }
public Step this[int index]
{
get { return (Step)List[index]; }
}
}
Step class:
[ToolboxItem(false),
DesignTimeVisible(false),
Serializable()]
public class Step : Component
{
public Step(string name) : this(name, null, StepLayout.DEFAULT_LAYOUT){ }
public Step(string name, Collection<Step> subSteps) : this(name, subSteps, StepLayout.DEFAULT_LAYOUT){ }
public Step(string name, Collection<Step> subSteps, StepLayout stepLayout)
{
this.Name = name;
this.SubSteps = subSteps;
this.Layout = stepLayout;
}
// In order to provide design-time support, a default constructor without parameters is required:
public static int NEW_ITEM_ID = 1;
public Step()
: this("Step" + NEW_ITEM_ID, null, StepLayout.DEFAULT_LAYOUT)
{
NEW_ITEM_ID++;
}
// Some more properties
}
CustomCollectionEditor:
class CustomCollectionEditor : CollectionEditor
{
private ITypeDescriptorContext mContext;
public CustomCollectionEditor(Type type) : base(type) { }
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
mContext = context;
return base.EditValue(context, provider, value);
}
protected override object CreateInstance(Type itemType)
{
if (itemType == typeof(Step))
{
Step s = (Step)base.CreateInstance(itemType);
s.parentContext = mContext; // Each step needs a reference to its parentContext at design time
return s;
}
return base.CreateInstance(itemType);
}
}
The things I already tried:
- Making the Step class a component as described here: http://www.codeproject.com/Articles/5372/How-to-Edit-and-Persist-Collections-with-Collectio
- Changing
Collection<Step>
to a custom collection classStepCollection
inheriting System.Collections.CollectionBase (also described in the previous code project article) - Setting the DesignerSerializationVisibility to Content as described here: Collection Editor within a User Control at Design Time When it is set to Visible, the designer assigns null to my property ; when it is set to Content, the designer assigns nothing.
- I also found this: How to make a UserControl with a Collection that can be edited at design time? but the CollectionBase class does this for me already.
- Debugging a lot, but since there are no exceptions I really don't know what's going wrong. When I added an event listener to the collectionForm's closing event, I could see the EditValue property (of the collectionForm) was still null even when I added a few steps in the collection editor. But I also don't know why that is...
When finishing this post, I just found this topic: Simplest way to edit a collection in DesignMode? It's exactly the same problem I experience, however I can't use the proposed answer because I don't use a standard collection.