2009-12-10 9 views
5

Estoy escribiendo una aplicación GUI donde necesito habilitar las propiedades de edición de objetos arbitrarios (sus tipos solo se conocen en tiempo de ejecución).PropertyGrid y tipos de objetos dinámicos

He decidido utilizar el control PropertyGrid para habilitar esta funcionalidad. creé la clase siguiente:

[TypeConverter(typeof(ExpandableObjectConverter))] 
[DefaultPropertyAttribute("Value")] 
public class Wrapper 
{ 
    public Wrapper(object val) 
    { 
     m_Value = val; 
    } 

    private object m_Value; 

    [NotifyParentPropertyAttribute(true)] 
    [TypeConverter(typeof(ExpandableObjectConverter))] 
    public object Value 
    { 
     get { return m_Value; } 
     set { m_Value = value; } 
    } 
} 

Cuando llego a una instancia de un objeto que necesito para editar, se crea un contenedor para él y establecerlo como el objeto seleccionado:

Wrapper wrap = new Wrapper(obj); 
propertyGrid.SelectedObject = wrap; 

Pero Me he encontrado con el siguiente problema: lo anterior funciona como se espera solo cuando el tipo de obj es un tipo personalizado (es decir, una clase que definí por mí mismo o un tipo complejo incorporado) pero no cuando obj es una primitiva.

Por ejemplo, si define:

[TypeConverter(typeof(ExpandableObjectConverter))] 
public class SomeClass 
{ 
    public SomeClass() 
    { 
     a = 1; 
     b = 2; 
    } 

    public SomeClass(int a, int b) 
    { 
     this.a = a; 
     this.b = b; 
    } 

    private int a; 

    [NotifyParentPropertyAttribute(true)] 
    public int A 
    { 
     get { return a; } 
     set { a = value; } 
    } 

    private int b; 

    [NotifyParentPropertyAttribute(true)] 
    public int B 
    { 
     get { return b; } 
     set { b = value; } 
    } 
} 

Y NO:

Entonces todo funciona hinchan. Por otro lado, cuando realizo el siguiente:

int num = 1; 
Wrapper wrap = new Wrapper(num); 
propertyGrid.SelectedObject = wrap; 

entonces puedo ver el valor "1" en la red (y no es en escala de grises) pero no puedo editar el valor. Noté que si cambio el tipo de propiedad de "Valor" de Wrapper a int y elimino el atributo TypeConverter, funciona. Obtengo el mismo comportamiento para otros tipos y cadenas primitivos.

¿Cuál es el problema?

¡Gracias de antemano!

Respuesta

5

Si configura ExpandableObjectConverter en su propiedad Value, no será editable y esto es normal porque CanConvertFrom devolverá false. SI elimina el convertidor de tipo, PropertyGrid utilizará el TypeConverter genérico y usted estará nuevamente en el mismo caso. Entonces, la solución consiste en adjuntar un TypeConverter más inteligente que actuará como un contenedor para el TypeConverter correcto. Aquí es una sucia (que tenía poco tiempo, llevará a cabo cuando sea necesario ya que acabo implementado la parte ConvertFrom):

public class MySmartExpandableObjectConverter : ExpandableObjectConverter 
{ 
    TypeConverter actualConverter = null; 

    private void InitConverter(ITypeDescriptorContext context) 
    { 
     if (actualConverter == null) 
     { 
      TypeConverter parentConverter = TypeDescriptor.GetConverter(context.Instance); 
      PropertyDescriptorCollection coll = parentConverter.GetProperties(context.Instance); 
      PropertyDescriptor pd = coll[context.PropertyDescriptor.Name]; 

      if (pd.PropertyType == typeof(object)) 
       actualConverter = TypeDescriptor.GetConverter(pd.GetValue(context.Instance)); 
      else 
       actualConverter = this; 
     } 
    } 

    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) 
    { 
     InitConverter(context); 

     return actualConverter.CanConvertFrom(context, sourceType); 
    } 

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) 
    { 
     InitConverter(context); // I guess it is not needed here 

     return actualConverter.ConvertFrom(context, culture, value); 
    } 
} 

Avísame si necesita ajustar algo.

Nicolas

+0

¡Muchas gracias, eso funcionó! :) – Marina

+0

¿Por qué esta línea 'parentConverter.GetProperties (context.Instance);' return null? –

0

Elimine el "TypeConverter" de la propiedad "Value", la propertygrid leerá el "TypConverter" del tipo de valor que está en la propiedad.

+1

lo probé, cuando hago esto la rejilla de propiedades muestra el valor de la propiedad correctamente, pero de color gris-escala y la edición está desactivada (lo hace incluso cuando obj no es un primitivo) – Marina

+0

Por desgracia, MS PropertyGrid no es tan inteligente, ya que no configura ningún convertidor en su propiedad Value. Para su int, no devolverá Int32Converter, sino TypeConverter. Lo sé porque tuve que manejar este caso en SPG. Vea mi respuesta para una solución alternativa. –

+0

Hmm, tienes razón. Hasta ahora he vivido convencido de que la red de propiedad es tan inteligente. Gracias – TcKs

Cuestiones relacionadas