Today at work, I stumbled upon a problem that was driving me nuts.
Basically my goal is this:
I have a UserControl1
, with a field of the type Collection<Class1>
and a corresponding property Collection<Class1> Prop
. Like this:
public class UserControl1 : UserControl
{
private Collection<Class1> field = null;
// later changed to:
//private Collection<Class1> field = new Collection<Class1>();
[Category("Data")]
[DefaultValue(null)]
[Description("asdf")]
public Collection<Class1> prop
{
get { return field; }
set { field = value; }
}
}
// later added:
//[Serializable]
public class Class1
{
private bool booltest; public bool Booltest { get...set...}
private int inttest; public int Inttest { get...set...}
}
If you already know what I screwed up: no need to read the rest. I am going to describe what exactly I did.
Now I put the UserControl
onto a random Form and change the Prop
property. A generic "Collection Editor" appears, like the one used for t开发者_StackOverflowhe columns and groups in a listview control. I can enter data as expected. However, when I click OK, the data is gone.
It took me over hour to figure out that I actually have to instantiate my field: private Collection<MyClass> field = new Collection<MyClass>();
. Very good, only that the designer entered superspazzing mode. Cascading nightmare error message that can be reduced to: "You must put [Serializable]
before your Class1
." After doing that I could actually put my UserControl1
on the Form again.
But that only works once. When opening the designer of the Form where I use the UserControl1
after editing something, it gives me an error:
Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'.
Well. The Error List says:
Warning: ResX file Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'. Line 134, position 5. cannot be parsed.
The designer tries to fetch the Property's data from the resx file. Removing the resx file "solves" that exactly once.
The Form can now be displayed again, with my UserControl1
. The Collection property is editable, and it is being saved. It actually works. Once. Whenever I change something and then try to open the Form's designer again, the above error occurs again. I can delete the resx file, but that will of course also delete my data.
Relevant resources that helped me so far (among a ton of not so helpful search results):
http://www.codeproject.com/Answers/190675/Usercontrol-with-custom-class-property#answer1
http://www.codeproject.com/KB/cs/propertyeditor.aspx http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=94 http://msdn.microsoft.com/en-us/library/system.runtime.serialization.iserializable.aspx(I also tried implementing ISerializable and overriding GetObjectData with
{ info.AddValue("testbool", testbool); info.AddValue("testint", testint); }
didn't help either (I also tried the property names instead of the field names))
Sorry for writing this like a bad horror novel btw.
What you want is a design time support with CodeDom serialization. You do not need SerializableAttribute
or ISerializable
, those are for binary serialization.
Since you want to serialize the collection, you must tell the designer to serialize it as such. That is done with the DesignerSerializationVisibiliby attribute - value of Content
tells the designer to serialize property contents rather than property itself. Contents of the property should of course be CodeDom serializable, which simple classes with simple properties are by default.
So if you change your UserControl1
class like this:
public class UserControl1 : UserControl
{
private Collection<Class1> field = new Collection<Class1>();
[Category("Data")]
[Description("asdf")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Collection<Class1> prop
{
get { return field; }
}
}
... it should do the trick. Oh and collection properties are usually not writeable, although that is not mandatory. But serializer expects the collection property to be initialized, that is why you had to add initialization for the field.
Another note, if you do not want that your property is marked with bold in the property editor, you can specify a more complex "default value" through a special method ShouldSerializePropertyName
, which can even be private. Like so:
private bool ShouldSerializeprop()
{
return (field.Count > 0);
}
Now your property will only be bold when it is not empty. But I digress, this was not a question :)
The perfect exemple is this:
public partial class SCon : UserControl
{
public SCon()
{
InitializeComponent();
if (Persoanas == null)
{
Persoanas = new List<Persoana>();
}
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<Persoan> Persoanas { get; set; }
}
[Serializable]
public class Persoan
{
public int Id { get; set; }
public String Name { get; set; }
}
Just change Collection<>
to List<>
精彩评论