65.9K
CodeProject is changing. Read more.
Home

The PropertyGrid: Overriding Class Attributes

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (13 votes)

Aug 2, 2007

CPOL

4 min read

viewsIcon

68863

downloadIcon

1557

Dynamically control any attribute, including DefaultValues, Categories, Descriptions, DisplayNames, ReadOnly attributes, Property sort order and more.

Screenshot - ScreenShot_DynDemo.gif

Introduction

The DynamicPropWrapper class wraps an existing class and filters the property information that the .NET PropertyGrid displays. The purpose for this is mainly to control the ReadOnly and DefaultValues for each property dynamically in the code. Other features include dynamic modification of the Categories, Descriptions, DisplayNames, Property sorting order and more.

  • Two methods for handling default values
  • Wraps an existing class, making it a drop-in solution
  • Overrides attributes with one line of code
  • Preserves all existing attribute information that may already be defined in your class
  • Add/override any attribute desired

Using the Code

To use the DynamicPropWrapper class, do the following:

// This is the class object whose properties you want
// to see in the PropertyGrid.

mTestObject = new DemoClass1;

// The DynamicPropWrapper is the Main class used
// to filter property information from the class above.

mDynPropWrapper = new DynamicPropWrapper(mTestObject);

// The PropertyGrid.SelectedObject gets set to the
// DynamicPropWrapper.DynamicDescriptor property. This
// allows the DynamicPropWrapper class to describe the
// type information for mTestObject.

propertyGrid1.SelectedObject = mDynPropWrapper.DynamicDescriptor;

Overriding Attributes

Overriding a property attribute can be done with one line of code:

// Overriding/Adding a DefaultValue

mDynPropWrapper["MyPropertyName"].Overrides.Replace_
        (new DefaultValueAttribute("New Default Value"));

// Overriding/Adding a ReadOnly

mDynPropWrapper["MyPropertyName"].Overrides.Replace_
                (new ReadOnlyAttribute(true));

The DefaultValue

First, note the following: PRB: XML Serialization: System.Xml.XmlSerializer Does Not Serialize Default Values. Microsoft recognized this as a problem in .NET 1.1 and claimed it would be resolved in its next framework release. Apparently it never got done. The result is that any class property whose value matches the default value will not be serialized by the XmlSerializer. This was no doubt done intentionally in an effort to reduce the size of the final output stream, but it also means that the class object it was serialized with is required to re-construct the data.

Using the DynamicPropWrapper class, you can omit DefaultValueAttributes from your classes and control the default value in two ways:

  1. By overriding the default values for each property - see the example above
  2. By using a global DefaultValueObject for all property default values - see the example below
// This is the class object whose properties you want
// to see in the PropertyGrid.

mTestObject = new DemoClass1;

// This is the class that represents the default values
// for mTestObject.

mTestObject_Defaults = new DemoClass1();

// The DynamicPropWrapper is the Main class used
// to filter property information from the class above.

mDynPropWrapper = new DynamicPropWrapper(mTestObject);

// Assign a global DefaultValueObject.

mDynPropWrapper.OverrideProps.DefaultValueObject = mTestObject_Defaults;

// The PropertyGrid.SelectedObject gets set to the
// DynamicPropWrapper.DynamicDescriptor property. This
// allows the DynamicPropWrapper class to describe the
// type information for mTestObject.

propertyGrid1.SelectedObject = mDynPropWrapper.DynamicDescriptor;

You can now use mTestObject_Defaults to manage the default values for mTestObject. The DynamicPropWrapper class will first look for a global DefaultValueObject. If one is not found, it looks in the attributes collection for a DefaultValueAttribute. If a DefaultValue override has been set, it will use this. If there is no DefaultValueObject and no DefaultValue override, it will use the "hard-coded" DefaultValueAttribute in the class (if one exists).

Property Sorting

Properties can be ordered in two ways:

  • Natural - Properties appear in the same order that they were defined in the code
  • UsePropertySortAttributes - You can apply a SortPropsByAttribute to each property. This class takes an Integer as an argument for sorting

NOTE: The PropertyGrid View ToolBar Buttons (Categorized/Alphabetical) will always set the PropertySort to either CategorizedAlphabetical or Alphabetical. This overrides any sorting done with the property descriptors. To remedy this, add an event handler to the PropertySortChanged event and force the PropertySort to either Categorized or None.

DynamicPropWrapper Members
Namespace:DynamicProps

Wrap this class around your class object and point the PropertyGrid SelectedObject property to DynamicPropWrapper.DynamicDescriptor for dynamic property control.

Constructors

  • DynamicPropWrapper() - This constructor is only used if DynamicPropWrapper is inherited
  • DynamicPropWrapper(Object instance) - Always use this constructor when wrapping a class

Parameter Name Type Description
instance Object The object whose properties are to be filtered

Methods

  • Object GetDefaultPropValue(String propName) - Returns the default value via the DynamicTypeDescriptor; this is the same value that the PropertyGrid will see when it asks for the DefaultValue.
  • Object GetPropValue(String propName) - Returns the property value via the DynamicTypeDescriptor; this is the same value that the PropertyGrid will see when it asks for the property value.

Properties

Property Name Type Accessors Description
Item DynPropertyOverride Get/Set (default) Indexer for accessing the OverrideProps property
DynamicDescriptor DynamicTypeDescriptor Get Returns the DynamicDescriptor object that is used by PropertyGrid
Instance Object Get/Set An instance of the class whose properties you want to dynamically filter/modify
OverrideProps DynPropertyOverrideList Get Dictionary list of the class properties that are being overridden. Each dictionary item contains a list of the attributes that are being overridden. Use this property (or the indexer) to view and manipulate the dynamic property information
PropertySortType DynPropertySortTypes Get/Set Change the order in which properties are listed in the PropertyGrid

Points of Interest

Although it was never intended, you can also inherit the DynamicPropWrapper class and it automatically adjusts to provide type information for the object that inherited it. If you choose to use it this way, don't set the Instance property. This will force it back to a non-inherited mode and it will consequently get stuck in an infinite loop. Here are some other articles at The Code Project that have similar functionality:

History

  • 01-12-2008: DynamicProps 1.2.0
    • Bug fixed: setting the Instance property forces the sort order to default
  • 08-04-2007: DynamicProps 1.1.0
    • Bug fixed: DefaultValueObject would not work unless at least one override attribute was set
    • Additional documentation added to demo source code
  • 07-30-2007: DynamicProps 1.0.0
    • Initial release