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:
mTestObject = new DemoClass1;
mDynPropWrapper = new DynamicPropWrapper(mTestObject);
propertyGrid1.SelectedObject = mDynPropWrapper.DynamicDescriptor;
Overriding Attributes
Overriding a property attribute can be done with one line of code:
mDynPropWrapper["MyPropertyName"].Overrides.Replace_
(new DefaultValueAttribute("New Default Value"));
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:
- By overriding the default values for each property - see the example above
- By using a global
DefaultValueObject
for all property default values - see the example below
mTestObject = new DemoClass1;
mTestObject_Defaults = new DemoClass1();
mDynPropWrapper = new DynamicPropWrapper(mTestObject);
mDynPropWrapper.OverrideProps.DefaultValueObject = mTestObject_Defaults;
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 inheritedDynamicPropWrapper(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
It started nearly 20 years ago. I was a BBS freak long before I could drive or even had a girl friend. I ran a type of software known at the time as Renegade; questionably a hacked version of another type of BBS software known as WWIV. Looking back I really had no choice. Renegade was free, fast and most importantly, open-source. Turbo Pascal was my flavor at the time, and I spent nearly all of my time with it; writing things from goofy SysOp pagers to label printing systems.
I'm a bit ashamed to say I can barely remember the basic "Pascal" syntax; I hear they call it Delphi or something now.. (lol)..
These days it's mainly all C#,C++/CLR syntax for me. And why not? That’s a powerful combination of rapid development, speed, compatibility, and flexibility. I'm sure most developers would agree that these days C# can't be beat for rapid development. It's powerful and even portable; a rare combination for a high-level language.
Language Experience: C#, C++/CLR, C, VB.NET, SQL, PHP, JavaScript, HTML, ASM