2012-05-07 27 views
7

Quiero mostrar varias instancias de una clase en mi PropertyGrid. La clase tiene este aspecto:Propiedad de solo lectura PropertyGrid en el nivel de objeto

public class Parameter 
{ 
    [Description("the name")] 
    public string Name { get; set; } 

    [Description("the value"), ReadOnly(true)] 
    public string Value { get; set; } 

    [Description("the description")] 
    public string Description { get; set; } 
} 

Tengo muchas instancias de esa clase en un TreeView. Cuando selecciono uno de ellos en mi TreeView, las propiedades aparecen en el PropertyGrid como se esperaba. Hasta ahora todo bien, pero quiero personalizar este comportamiento de la siguiente manera:

Para cada instancia individual, deseo poder evitar que el usuario modifique una propiedad específica. Configurando ReadOnly(true) dentro de mi clase (como puede ver en el ejemplo anterior), todas las propiedades de Value se desactivarán en un de nivel de clase.

Después de algunas investigaciones he encontrado la solución después de lo que me da la oportunidad de activar/desactivar una propiedad específica en tiempo de ejecución:

PropertyDescriptor descriptor = TypeDescriptor.GetProperties(this)["Value"]; 

ReadOnlyAttribute attr = 
     (ReadOnlyAttribute)descriptor.Attributes[typeof(ReadOnlyAttribute)]; 

FieldInfo isReadOnly = attr.GetType().GetField(
     "isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance); 

isReadOnly.SetValue(attr, false); 

Este enfoque funciona muy bien, pero por desgracia también en un solo nivel de clase. Esto significa que si configuro Value 's isReadOnly en false, todos de mis Parameter -objetos tienen la propiedad Value escribible. Pero quiero SOLO esto en ese objeto en particular (por lo tanto, nivel de objeto). Realmente no quiero crear clases separadas para las propiedades de lectura/escritura y de solo lectura.

Como estoy quedando sin ideas, su ayuda es muy apreciada :)

Gracias de antemano!

EDITAR: Necesito que las propiedades de solo lectura estén atenuadas, por lo que el usuario puede ver que no está permitido o posible editarlas.

Respuesta

4

EDITAR: Vinculado artículo ha sido eliminado (espero sólo temporal). Puede encontrar una alternativa viable en las respuestas al How to add property-level Attribute to the TypeDescriptor at runtime?. Básicamente tiene que agregar (en tiempo de ejecución) ReadOnlyAttribute a través de un TypeDescriptor para esa propiedad.


Tome un vistazo a este viejo pero agradable article on CodeProject, que contiene una gran cantidad de herramientas útiles para la PropertyGrid.

Básicamente, usted proporciona una clase o un delegado que se utilizará para obtener los atributos de sus propiedades. Como se invocará pasando la instancia del objeto para el que desea obtener atributos, podrá devolver (o no) el ReadOnlyAttribute por objeto.En breve: aplique un PropertyAttributesProviderAttribute a su propiedad, escriba su propio proveedor y reemplace los atributos de la colección PropertyAttributes basada en el objeto mismo (y no en la clase)

+0

He leído todo el documento pero todavía no entiendo su idea. ¿Podría proporcionarme un pequeño ejemplo de código para hacerlo un poco más claro? Gracias por su tiempo :) –

+0

Vea el párrafo * Uso dinámico * en ese artículo. En breve: aplique un atributo PropertyAttributesProviderAttribute a su propiedad, escriba su propio proveedor y reemplace los atributos de la colección PropertyAttributes en función del objeto mismo (y no de la clase). –

+0

Como puedo ver en el código fuente, ¿esto requiere usar la implementación personalizada PropertyGrid de los autores para que funcione? En mi caso, tengo que usar un PropertyGrid existente que está dentro de una DLL (que no puedo modificar). –

1

Puede envolver el objeto con un descriptor de tipo personalizado, pero creo que sería excesivo, porque debe crear una nueva clase derivada de tipodescriptor.

Por lo tanto, una solución más simple sería tener una bandera, algo así como:

public class Parameter 
{ 
    private string thevalue; 

    [Browsable(false)] 
    public bool CanEditValue { get; set; } 

    [Description("the name")] 
    public string Name { get; set; } 

    [Description("the description")] 
    public string Description { get; set; } 

    [Description("the value"), ReadOnly(true)] 
    public string Value { 
     get { return this.thevalue; } 
     set { if (this.CanEditValue) this.thevalue = value; } 
    } 
} 
+0

hola Jaime, su sugerencia de duplicar las propiedades sería aceptable porque es realmente sencillo. Intenté esto y desafortunadamente consultar dentro del setter no deshabilita la edición de propiedades como ReadOnly (true) ... por lo que no está atenuado. los usuarios pensarán que es modificable, pero sus comentarios serán descartados. cualquier otra idea menos compleja? :) –

+0

Me temo que su única opción es derivar un descriptor de propiedad e implementar el getter de propiedad IsReadOnly condicional. –

Cuestiones relacionadas