Come rendere modificabile la proprietà User control di tipo Collection in Form Designer?

Oggi al lavoro, mi sono imbattuto in un problema che mi stava facendo impazzire.

Fondamentalmente il mio objective è questo:

Ho un UserControl1 , con un campo del tipo Collection e una Collection Prop proprietà corrispondente Collection Prop . Come questo:

 public class UserControl1 : UserControl { private Collection field = null; // later changed to: //private Collection field = new Collection(); [Category("Data")] [DefaultValue(null)] [Description("asdf")] public Collection 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...} } 

Se già sai cosa ho rovinato: non c’è bisogno di leggere il resto. Ho intenzione di descrivere cosa esattamente ho fatto.

Ora metto l’ UserControl su un modulo casuale e cambio la proprietà Prop . Viene visualizzato un “Editor raccolta” generico, come quello utilizzato per le colonne e i gruppi in un controllo listview. Posso inserire i dati come previsto. Tuttavia, quando faccio clic su OK, i dati sono andati.

Mi ci è voluto più di un’ora per capire che in realtà devo istanziare il mio campo: private Collection field = new Collection(); . Molto buono, solo che il designer è entrato in modalità superspazzing. Messaggio di errore dell’incubo a cascata che può essere ridotto a: “Devi mettere [Serializable] prima della tua Class1 .” Dopo averlo fatto, avrei potuto inserire nuovamente il mio UserControl1 nel modulo.

Ma funziona solo una volta. Quando si apre il designer del Form dove utilizzo UserControl1 dopo aver modificato qualcosa, mi dà un errore:

Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'.

Bene. La lista degli errori dice:

Warning: ResX file Object of type 'userctltest.Class1[]' cannot be converted to type 'userctltest.Class1[]'. Line 134, position 5. cannot be parsed.

Il progettista tenta di recuperare i dati della proprietà dal file resx. La rimozione del file resx “risolve” esattamente una volta.

Il modulo può ora essere visualizzato di nuovo, con il mio UserControl1 . La proprietà Collection è modificabile e viene salvata. Funziona davvero. Una volta. Ogni volta che cambio qualcosa e poi provo ad aprire di nuovo il designer di Form, l’errore sopra riportato si ripresenta. Posso cancellare il file resx, ma ovviamente cancellerò anche i miei dati.

Risorse rilevanti che mi hanno aiutato finora (tra un sacco di risultati di ricerca non così utili):

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

(Ho anche provato a implementare ISerializable e sovrascrivere GetObjectData con

{ info.AddValue("testbool", testbool); info.AddValue("testint", testint); }

non ha aiutato neanche (ho anche provato i nomi delle proprietà al posto dei nomi dei campi))

Scusa per aver scritto questo come un brutto romanzo horror btw.

Quello che vuoi è un supporto del tempo di progettazione con serializzazione CodeDom. Non hai bisogno di SerializableAttribute o ISerializable , quelli sono per la serializzazione binaria. Dato che vuoi serializzare la collezione, devi dire al designer di serializzarla come tale. Ciò avviene con l’attributo DesignerSerializationVisibiliby : il valore di Content indica al designer di serializzare i contenuti delle proprietà piuttosto che la proprietà stessa. I contenuti della proprietà dovrebbero ovviamente essere serializzabili con CodeDom, che per default sono semplici classi con proprietà semplici.

Quindi se cambi la tua class UserControl1 questo modo:

 public class UserControl1 : UserControl { private Collection field = new Collection(); [Category("Data")] [Description("asdf")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public Collection prop { get { return field; } } } 

… dovrebbe fare il trucco. Oh e le proprietà della collezione di solito non sono scrivibili, anche se non è obbligatorio. Ma serializzatore si aspetta che la proprietà della raccolta sia inizializzata, ecco perché è stato necessario aggiungere l’inizializzazione per il campo. Un’altra nota, se non si desidera che la proprietà sia contrassegnata in grassetto nell’editor delle proprietà, è ansible specificare un “valore predefinito” più complesso tramite un metodo speciale ShouldSerializePropertyName , che può anche essere privato. Così:

 private bool ShouldSerializeprop() { return (field.Count > 0); } 

Ora la tua proprietà sarà in grassetto solo quando non è vuota. Ma sto divagando, questa non era una domanda 🙂

L’esempio perfetto è questo:

 public partial class SCon : UserControl { public SCon() { InitializeComponent(); if (Persoanas == null) { Persoanas = new List(); } } [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public List Persoanas { get; set; } } [Serializable] public class Persoan { public int Id { get; set; } public String Name { get; set; } } 

Basta cambiare la Collection<> alla List<>