Inferno Inferno - 2 months ago 22
C# Question

PropertyGrid readonly property on object-level

I want to display multiple instances of one class in my

PropertyGrid
. The class looks like this:

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


I have many instances of that class in a
TreeView
. When I select one of them in my
TreeView
, the properties are getting displayed right in the
PropertyGrid
.

And here comes my problem...

For each single instance I want to be able to disable editing so the user cannot modify a specific property. By setting
ReadOnly(true)
within my class, all
Value
properties will be disabled on a class-level.

After some research I found the following solution which gives me the opportunity to enable/disable a specific property at runtime (this is what I need):

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


This solution works just fine but unfortunately also on class-level only. This means if I set the
Value
's
isReadOnly
to
false
, all of my
Parameter
-objects have the
Value
property writeable. But I want this ONLY on that one particular object (thus object-level). I really don't want to create separate classes for read/write and readonly properties.

As I am running out of ideas, your help is much appreciated :)

Thanks in advance!

EDIT: I need the readonly properties to be grayed-out, so the user can see that it is disabled for editing.

Answer

EDIT: Linked article has been removed (I hope just temporary). You can fine a viable alternative in answers to How to add property-level Attribute to the TypeDescriptor at runtime?. Basically you have to add (at run-time) ReadOnlyAttribute through a TypeDescriptor for that property.


Take a look at this old but nice article on CodeProject, it contains a lot of useful tools for the PropertyGrid.

Basically you provide a class or a delegate that will be used to get the attributes of your properties. Because it will be invoked passing the instance of the object you want to get attributes for then you'll be able to return (or not) the ReadOnlyAttribute with a per object basis. Shortly: apply a PropertyAttributesProviderAttribute to your property, write your own provider and replace attributes from the PropertyAttributes collection based on the object itself (and not on the class)