2012-05-07 16 views
7

Desidero visualizzare più istanze di una classe nel mio PropertyGrid. La classe assomiglia a questo:PropertyGrid proprietà readonly a livello di oggetto

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

Ho molte istanze di quella classe in un TreeView. Quando seleziono uno di essi nel mio TreeView, le proprietà appaiono nello PropertyGrid come previsto. Fin qui tutto bene, ma voglio personalizzare questo comportamento nel modo seguente:

Per ogni singola istanza, voglio essere in grado di impedire all'utente di modificare una proprietà specifica. Impostando ReadOnly(true) nella mia classe (come puoi vedere nell'esempio sopra), tutte le proprietà Value verranno disabilitate su un livello di classe.

Dopo alcune ricerche ho trovato la seguente soluzione che mi dà la possibilità di abilitare/disabilitare una specifica proprietà in fase di esecuzione:

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

Questo approccio funziona bene, ma purtroppo anche in unica classe di livello. Ciò significa che se imposto il numero , del Parameter - gli oggetti hanno la proprietà Value scrivibile. Ma lo voglio SOLO su quell'unico oggetto particolare (quindi a livello di oggetto). Non voglio davvero creare classi separate per le proprietà read/write e readonly.

Come io sono a corto di idee, il vostro aiuto è molto apprezzato :)

Grazie in anticipo!

MODIFICA: ho bisogno che le proprietà di sola lettura siano disattivate, in modo che l'utente possa vedere che non è consentito o possibile modificarle.

risposta

4

EDIT: Collegato articolo è stato rimosso (spero solo temporanea). Puoi trovare una valida alternativa nelle risposte a How to add property-level Attribute to the TypeDescriptor at runtime?. Fondamentalmente è necessario aggiungere (in fase di esecuzione) ReadOnlyAttribute tramite un TypeDescriptor per quella proprietà.


Date un'occhiata a questo vecchio ma bello article on CodeProject, contiene un sacco di utili strumenti per il PropertyGrid.

In pratica si fornisce una classe o un delegato che verrà utilizzato per ottenere gli attributi delle proprietà. Poiché verrà invocato il passaggio dell'istanza dell'oggetto per il quale si desidera ottenere gli attributi, sarà possibile restituire (o meno) lo ReadOnlyAttribute con una base per oggetto.In breve: applica un PropertyAttributesProviderAttribute alla tua proprietà, scrivi il tuo provider e sostituisci gli attributi della collezione PropertyAttributes in base all'oggetto stesso (e non alla classe)

+0

Ho letto l'intero documento ma ancora non capisco la tua idea. Potresti fornirmi un piccolo esempio di codice per renderlo un po 'più chiaro? Grazie per il tuo tempo :) –

+0

Consulta il paragrafo * Uso dinamico * in quell'articolo. In breve: applica un PropertyAttributesProviderAttribute alla tua proprietà, scrivi il tuo provider e sostituisci gli attributi dall'insieme PropertyAttributes basato sull'oggetto stesso (e non sulla classe). –

+0

Come posso vedere nel codice sorgente, è necessario utilizzare l'implementazione PropertyGrid personalizzata dell'autore per farlo funzionare? Nel mio caso devo usare un PropertyGrid esistente che si trova all'interno di una DLL (che non posso modificare). –

1

È possibile avvolgere l'oggetto con un descrittore di tipo personalizzato, ma penso che sarebbe eccessivo, perché è necessario creare una nuova classe derivata da typedescriptor.

Quindi, una soluzione più semplice sarebbe quella di avere una bandiera, qualcosa come:

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

ciao Jaime, il tuo suggerimento con proprietà di raddoppio sarebbe accettabile perché è davvero semplice. Ho provato questo e sfortunatamente il controllo all'interno del setter non disabilita la modifica delle proprietà come ReadOnly (true) ... quindi non è oscurato. gli utenti penseranno che sia modificabile ma il loro input verrà semplicemente scartato. altre idee meno complesse? :) –

+0

Temo che l'unica opzione sia quella di derivare un descrittore di proprietà e implementare il getter di proprietà IsReadOnly condizionale. –