7

Je souhaite afficher plusieurs instances d'une classe dans PropertyGrid. La classe ressemble à ceci:Propriété PropertyGrid readonly au niveau de l'objet

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

J'ai de nombreux cas de cette classe dans un TreeView. Lorsque je sélectionne l'un d'entre eux dans mon TreeView, les propriétés s'affichent dans le PropertyGrid comme prévu. Jusqu'ici tout va bien, mais je veux personnaliser ce comportement de la manière suivante:

Pour chaque instance, je veux pouvoir empêcher l'utilisateur de modifier une propriété spécifique. En définissant ReadOnly(true) dans ma classe (comme vous pouvez le voir dans l'exemple ci-dessus), toutes les propriétés Value seront désactivées sur un de classe.

Après quelques recherches, je trouve la solution suivante qui me donne la possibilité d'activer/désactiver une propriété spécifique à l'exécution:

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

Cette approche fonctionne très bien, mais malheureusement aussi la classe de niveau seulement. Cela signifie que si je mets le ValueisReadOnly à false, tous de mes Parameter -objets ont la propriété Value en écriture. Mais je veux que ce seul sur cet objet particulier (de niveau objet). Je ne veux vraiment pas créer des classes séparées pour les propriétés read/write et readonly.

Comme je suis à court d'idées, votre aide est très appréciée :)

Merci à l'avance!

EDIT: J'ai besoin que les propriétés readonly soient grisées, afin que l'utilisateur puisse voir qu'il n'est pas permis ou possible de les éditer.

Répondre

4

EDIT: article lié a été supprimé (je l'espère que temporaire). Vous pouvez affiner une alternative viable dans les réponses à How to add property-level Attribute to the TypeDescriptor at runtime?. Fondamentalement, vous devez ajouter (au moment de l'exécution) ReadOnlyAttribute à travers un TypeDescriptor pour cette propriété.


Jetez un oeil à ce vieux mais agréable article on CodeProject, il contient beaucoup d'outils utiles pour la PropertyGrid.

Fondamentalement, vous fournissez une classe ou un délégué qui sera utilisé pour obtenir les attributs de vos propriétés. Comme il sera appelé en passant l'instance de l'objet pour lequel vous voulez obtenir des attributs, vous pourrez retourner (ou non) le ReadOnlyAttribute avec une base par objet.En peu de temps: appliquez un PropertyAttributesProviderAttribute à votre propriété, écrivez votre propre fournisseur et remplacez les attributs de la collection PropertyAttributes basée sur l'objet lui-même (et non sur la classe)

+0

J'ai lu tout le document mais je ne comprends toujours pas votre idée. Pourriez-vous me fournir un petit exemple de code pour le rendre un peu plus clair? Merci pour votre temps :) –

+0

Voir le paragraphe * Utilisation dynamique * dans cet article. En bref: appliquez un PropertyAttributesProviderAttribute à votre propriété, écrivez votre propre fournisseur et remplacez les attributs de la collection PropertyAttributes par l'objet lui-même (et non par la classe). –

+0

Comme je peux le voir dans le code source, cela nécessite d'utiliser l'implémentation de PropertyGrid personnalisée par les auteurs pour le faire fonctionner? Dans mon cas, je dois utiliser un PropertyGrid existant qui se trouve dans une DLL (que je ne peux pas modifier). –

1

Vous pouvez envelopper l'objet avec un descripteur de type personnalisé, mais je pense que ce serait trop, car vous devez créer une nouvelle classe dérivée de typedescriptor.

Ainsi, une solution la plus simple serait d'avoir un drapeau, quelque chose comme:

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

bonjour Jaime, votre suggestion avec doubler des propriétés serait acceptable parce que c'est vraiment simple. J'ai essayé ceci et malheureusement vérifier dans le setter ne désactive pas l'édition de propriété comme ReadOnly (true) ... donc ce n'est pas grisé. les utilisateurs penseront qu'il est modifiable, mais leur entrée sera simplement rejetée. d'autres idées moins complexes? :) –

+0

Je crains que votre unique option est de dériver un descripteur de propriété et d'implémenter le getter de propriété conditionnelle IsReadOnly. –

Questions connexes