Introduction
In my last article, I described a control that extends the functionality of the System.Windows.Forms.PropertyGrid
. Now, let’s demonstrate the control. This diagram illustrates how the system property grid displays items:
Activity Diagram 1
PropertGrid
selects an object derived from the System.ComponentModel.ICustomTypeDescriptor
interface used by the SelectedObject
property.
PropertGrid
invokes the ICustomTypeDescriptor::GetProperties()
method and gets the System.ComponentModel.PropertyDescriptorCollection
object that contains the collection of System.ComponentModel.PropertyDescriptor
objects.
- Using the methods and properties of the
System.ComponentModel.PropertyDescriptor
object, PropertGrid
gets the description of each item (for example: display name, value, and others).
- If an item contains sub-items, then the
PropertyDescriptor
object should return an appropriate object derived from the System.ComponentModel.ICustomTypeDescriptor
interface that describes a child item, through the GetValue()
method. If an item has a simple system type, then this method returns just one.
Examine how the Puma.Controls.PropertyGrid
provides the necessary data for the system property grid:
Here is a reference of the extended interfaces:
IPropertyGridItemEx is derived from IPropertyGridItem
Provides auxiliary information about the item, most essential being the appropriate PropertyDescriptor
object that is used by the property grid for displaying the item (see how the system property grid displays an item).
Has the following properties and methods:
Properties:
System.ComponentModel.PropertyDescriptor PropertyDescriptor {get;}
Returns the PropertyDescriptor
object that describes the item.
IPropertyGridItemsEx ChildsEx {get;}
Returns the IPropertyGridItemsEx
interface for the item. If the interface has not yet been created, return null
.
IPropertyGridItemRootEx RootItemEx {get;}
Returns the root item of the items tree.
IPropertyGridItem BaseItem {get;}
Returns the base IPropertyGridItem
interface for this item.
int Index {get;}
Returns the index of the element in the parent’s child fragment collection.
Remark:
This is the index relative to the first item in the fragment (see the IPropertyGridChildItemsFragment
description), not to the child container (see the IPropertyGridChildItems
description).
bool IsCategory {get;}
Returns a flag indicating whether the item represents a category item.
Remark:
IsCategory
returns true
if this item is a sub-root item. In this case, when the property grid is displayed in Category mode and PropertyGrid.FirstItemsAsCategories = true
, then the item is displayed as the category for all of its child items.
Methods:
IPropertyGridItemsEx CreateChildsEx()
Creates and returns the IPropertyGridItemsEx
interface for the item.
string OnValueValidate(string Value);
Validates the value changed by the user before it is recorded by the property grid. Accepts a new value from the user, validates it, reformats it if necessary, and returns.
IPropertyGridChildItemsEx derived from IPropertyGridChildItems
Properties:
Puma.Controls.PropertyGridEx
activity diagram:
Activity Diagram 2
Notice:
- When the diagram indicates what should be created for an interface, this means that a class is created that implements this interface (in the Puma.Control.PropertyGridEx project, these classes are
PropertyGridChildItemsExImpl
and PropertyGridItemExImpl
for IPropertyGridChildItemsEx
and IPropertyGridItemEx
, respectively).
It is clear that not all sequenced activities that accomplish these interfaces are strictly defined. What is important for the robust functionality of this system is that all members of the base interface are implemented, in what manner does not matter.
PropertyGrid.GetProperties
returns a collection which contains a PropertyDescriptor
object whose GetValue()
method returns a PropertyGridItem
object or simply a string value. If it returns a PropertyGridItem
object, execute all sequence of actions in the same order, beginning from the PropertyGrid.GetProperties
operation.
When an item displayed by the property grid invokes its methods and properties of the appropriate PropertyDescriptor
object (see Activity diagram 1), for the purpose of this project, all these invocations are delegated to the PropertyGridItemEx
object (see Activity diagram 2), since we want to change the default representation of an item in the property grid with the appropriate overridden methods and properties of the PropertyGridItemEx
object. This is why we need to derive a class from the PropertyGridItemEx
class and override the necessary properties.
Example:
public class NewPropertyGridItemExImpl :
Puma.Controls.PropertyGrid.PropertyGridItemExImpl
{
...
public override string Value
{
get
{
return "[Changed value representation]" + base.Value;
}
set
{
base.Value = value;
}
}
...
Now implement this class used by the property grid in the place of the base class. This should override the PropertyGridItemRootExImpl
, PropertyGridItemExImpl
, and PropertyGridChildItemsExImpl
classes.
Schematically:
To see how this class is implemented in the current project, see the PropertyGridItemExImpl.cs, PropertyGridItemRootExImpl.cs, and the PropertyGridChildItemsExImpl.cs files.
Thanks to Arnie Berg for his contribution in this article writing.