4

I am defining a custom class to be used with the PropertyGrid control. Say, one of the properties is defined as such:

[CategoryAttribute("Section Name"),
DefaultValueAttribute("Default value"),
DescriptionAttribute("My property description")]
public string MyPropertyName
{
    get { return _MyPropertyName; }
    set { _MyPropertyName = value; }
}

private string _MyPropertyName;

As you see DefaultValueAttribute defines a default value for the property. Such default value is used in two cases:

  1. If this property value is changed from the default one the PropertyGrid control will display it in bold, and

  2. If I call ResetSelectedProperty method of the PropertyGrid, it will apply that default value to a selected cell.

This concept works fine, except one limitation of the DefaultValueAttribute. It accepts only a constant value. So I'm curious, can I set it dynamically, say, from a constructor or later in the code?

EDIT: I was able to find this code that lets me read the DefaultValueAttribute:

AttributeCollection attributes = TypeDescriptor.GetProperties(this)["MyPropertyName"].Attributes;
DefaultValueAttribute myAttribute = (DefaultValueAttribute)attributes[typeof(DefaultValueAttribute)];
string strDefaultValue = (string)myAttribute.Value;

The question is, how do you set it?

c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • The DefaultValueAttribute does not set the property to the value, it is purely informational... check this http://stackoverflow.com/questions/705553/net-defaultvalueattribute-on-properties . – Mate Nov 03 '13 at 04:46
  • @Mate: OK. So how do I set the default value then? The one that is used by the `ResetSelectedProperty` method. – c00000fd Nov 03 '13 at 08:54
  • You cannot use the attribute to do this, attributes apply to a type, not an object. You'll have to provide a custom PropertyDescriptor instead. Override its CanResetValue, ResetValue and ShouldSerializeValue members. Lots of code required although they are all just one-liners, a decent google query is ".net custom propertydescriptor". – Hans Passant Nov 03 '13 at 10:58
  • @HansPassant: I don't know. I'm ready to throw in the towel. I don't know how the heck they implemented it. I already wasted a day trying to figure it out. I think I'll just add an object property and write my own `ResetSelectedProperty` method to use it... there's not much help otherwise. – c00000fd Nov 03 '13 at 23:03
  • If this would work perfectly then nobody would ever have to write their own GUI program anymore. You'd just point the code generator to the declaration of your class and press the Magic button. Not that you'd really ever need you to do that, that job got outsourced to an Asian country a long time ago. – Hans Passant Nov 03 '13 at 23:27

1 Answers1

16

Finally, I got the answer! I've been running into a bunch of sites showing how to implement ICustomTypeDescriptor and PropertyDescriptor (here's one), which is fine if you want to add literally two pages of code to your 10-line class.

Here's a much faster way. I found a hint here. Bless those who actually post constructive ideas!

So the answer is to provide two methods in your class. One is private bool ShouldSerializePPP() and another one is private void ResetPPP() where PPP is your property name. The former method will be called by the PropertyGrid to determined if the property value was changed from a default one, and the latter method will be called whenever the PropertyGrid item is reset to a default value.

Here's how my class should look with these additions, that will allow to set a default value for a property at a run-time:

[CategoryAttribute("Section Name"),
DescriptionAttribute("My property description")]
public string MyPropertyName
{
    get { return _MyPropertyName; }
    set { _MyPropertyName = value; }
}
private bool ShouldSerializeMyPropertyName()
{
    //RETURN:
    //      = true if the property value should be displayed in bold, or "treated as different from a default one"
    return !(_MyPropertyName == "Default value");
}
private void ResetMyPropertyName()
{
    //This method is called after a call to 'PropertyGrid.ResetSelectedProperty()' method on this property
   _MyPropertyName = "Default value";
}

private string _MyPropertyName;
c00000fd
  • 20,994
  • 29
  • 177
  • 400
  • Thank you! Very, very helpful. – Glenn Jun 21 '16 at 14:22
  • If you combine this with implementing `IXmlSerializable` then the latter wins when you serialize the object (i.e. the property is serialized) and `ShouldSerializeXXX()` still controls whether the value is rendered in bold in the PropertyGrid so you get the best of both worlds. – Ian Goldby Jun 29 '18 at 08:14
  • I don't know if this is something speicific to the devexpress propertygrid but I had to make the above functions public to make it work – Tim Rutter Apr 28 '20 at 07:18