2011-09-15 10 views
11

Oggi al lavoro, mi sono imbattuto in un problema che mi stava facendo impazzire.Come rendere modificabile una proprietà User control di tipo Collection <MyClass> in Form Designer?

Fondamentalmente il mio obiettivo è questo:

Ho un UserControl1, con un campo di tipo Collection<Class1> e un corrispondente di proprietà Collection<Class1> Prop. Come questo:

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...} 
}

Se sai già che cosa ho fatto un casino: non c'è bisogno di leggere il resto. Ho intenzione di descrivere cosa esattamente ho fatto.

Ora inserisco lo UserControl in 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 sono voluti più di un'ora per capire che io in realtà devo istanziare mio campo: private Collection<MyClass> field = new Collection<MyClass>();. Molto buono, solo che il designer è entrato in modalità superspazzing. Messaggio di errore dell'incubo in cascata che può essere ridotto a: "Devi inserire [Serializable] prima del tuo Class1". Dopo averlo fatto, ho potuto inserire di nuovo il mio UserControl1 nel modulo.

Ma questo funziona solo una volta. Quando si apre il progettista del modulo in cui uso il UserControl1 dopo la modifica 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 struttura dal file resx. La rimozione del file resx "risolve" esattamente una volta.

Il modulo può essere visualizzato di nuovo, con la mia 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 (fra una tonnellata di risultati di ricerca non così utile):

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 attuazione ISerializable e prioritario GetObjectData con

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

non aiutano (ho provato anche i nomi di proprietà invece dei nomi di campo))

Siamo spiacenti per la scrittura di questo come un romanzo horror cattivo btw.

risposta

11

Quello che vuoi è un supporto per la progettazione con serializzazione CodeDom. Non è necessario SerializableAttribute o ISerializable, quelli sono per la serializzazione binaria. Poiché si desidera serializzare la raccolta, è necessario comunicare al progettista di serializzarla come tale. Questo viene fatto con l'attributo DesignerSerializationVisibiliby - il valore di Content indica al progettista di serializzare il contenuto della 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 si cambia la classe UserControl1 come questo:

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; } 
    } 
} 

... 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à, è possibile specificare un "valore predefinito" più complesso tramite un metodo speciale ShouldSerializePropertyName, che può anche essere privato. Mi piace così:

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

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

+0

che sembrava funzionare. Anche se la prima volta che l'ho provato, il progettista è tornato di nuovo in onda (blah non serializzabile bla). Dopo un'ora di giocherellare senza cambiare nulla alla fine (ho controllato la sovversione) ha funzionato perfettamente. Questa è la cosa più strana di sempre:/Grazie – dialer

+0

Se il controllo utente si trova nello stesso progetto del modulo, è necessario creare il progetto prima di utilizzare il controllo utente. Designer esamina l'assembly compilato e non il codice. – Patko

2

L'exemple perfetto è questo:

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; } 
    } 
0

Basta cambiare Collection<>-List<>

Problemi correlati