2011-09-15 15 views
11

Hoy en el trabajo, me encontré con un problema que me estaba volviendo loco.¿Cómo hacer que una propiedad de control de usuario de tipo Colección <MyClass> se pueda editar en el Diseñador de formularios?

Básicamente mi meta es la siguiente:

Tengo un UserControl1, con un campo del tipo Collection<Class1> y una propiedad correspondiente Collection<Class1> Prop. De esta manera:

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

Si ya sabe lo que la pata: no hay necesidad de leer el resto. Voy a describir exactamente lo que hice.

Ahora puse el UserControl en un Formulario aleatorio y cambio la propiedad Prop. Aparece un "Editor de colecciones" genérico, como el utilizado para las columnas y grupos en un control de vista de lista. Puedo ingresar datos como se esperaba Sin embargo, cuando hago clic en Aceptar, los datos desaparecen.

Me tomó más de una hora darme cuenta de que realmente tengo que crear una instancia de mi campo: private Collection<MyClass> field = new Collection<MyClass>();. Muy bien, solo que el diseñador ingresó al modo superspazzing. Mensaje de error de pesadilla en cascada que se puede reducir a: "Debe poner [Serializable] antes de su Class1". Después de hacer eso, pude poner mi UserControl1 nuevamente en el Formulario.

Pero eso solo funciona una vez. Al abrir el diseñador de la forma en que utilizo el UserControl1 después de editar algo, me da un error:

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

Bueno. La lista de errores dice:

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

El diseñador intenta obtener los datos de la propiedad de la resx. Eliminar el archivo resx "resuelve" eso exactamente una vez.

El formulario ahora se puede mostrar de nuevo, con mi UserControl1. La propiedad de recopilación es editable y se está guardando. En realidad funciona Una vez. Cada vez que cambio algo y luego intento abrir nuevamente el diseñador del Formulario, el error anterior aparece nuevamente. Puedo eliminar el archivo resx, pero eso también borrará mis datos.

recursos pertinentes que me ayudaron hasta el momento (entre un montón de resultados de la búsqueda no tan votos):

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

(que también intentaron implementar ISerializable y primordial GetObjectData con

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

tampoco ayudó (también probé los nombres de propiedad en lugar de los nombres de campo))

siento por escribir esto como una mala novela de terror por cierto.

Respuesta

11

Lo que quiere es un soporte de tiempo de diseño con serialización CodeDom. No necesita SerializableAttribute o ISerializable, que son para la serialización binaria. Dado que desea serializar la colección, debe decirle al diseñador que la serialice como tal. Esto se hace con el atributo DesignerSerializationVisibiliby; el valor de Content le dice al diseñador que serialice los contenidos de la propiedad en lugar de la propiedad misma. El contenido de la propiedad debe ser, por supuesto, serializable por CodeDom, que clases simples con propiedades simples son por defecto.

Así que si cambia de clase UserControl1 así:

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

... que debe hacer el truco. Ah, y las propiedades de recopilación generalmente no se pueden escribir, aunque eso no es obligatorio. Pero el serializador espera que la propiedad de la colección se inicialice, es por eso que usted tuvo que agregar la inicialización para el campo. Otra nota, si no desea que su propiedad esté marcada con negrita en el editor de propiedades, puede especificar un "valor predeterminado" más complejo a través de un método especial ShouldSerializePropertyName, que incluso puede ser privado. De esta manera:

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

Ahora su propiedad solo será brillante cuando no esté vacía. Pero me estoy desviando, esto no era una pregunta :)

+0

Eso parecía funcionar. Aunque cuando lo probé por primera vez, el diseñador se espació de nuevo (bla, no es blarable serializable). Después de una hora de manipulación, sin cambiar nada al final (comprobé la subversión), funcionó a la perfección. Esto es lo más extraño de la historia:/Gracias – dialer

+0

Si su control de usuario está en el mismo proyecto que el formulario, entonces debe compilar el proyecto antes de usar el control de usuario. El diseñador observa el ensamblado compilado y no su código. – Patko

2

El exemple perfecta es la siguiente:

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

Sólo cambia Collection<> a List<>

Cuestiones relacionadas