Click here to Skip to main content
14,271,826 members

PropertyGrid utilities

Rate this:
4.90 (40 votes)
Please Sign up or sign in to vote.
4.90 (40 votes)
7 Jan 2016CPOL
An article on sorting and globalization of properties in a PropertyGrid.

Image 1

Image 2


This article is on sorting and globalization of properties in a PropertyGrid.


  • Declarative (static) definition of property behaviour: property order, DisplayName, globalization of DisplayName, Description, and Category.
  • Dynamic definition of property behaviour using a call back. For each property, a property attributes provider can be set in which all attributes mentioned above can be overridden. Also, IsBrowsable and IsReadOnly can be modified at runtime.
  • Use the Tab key for tabbing through items.
  • Globalized tool tips of tool bar buttons.

It's easy to use and has ways to modify the place it looks for resources.


I ripped code from two projects, fused and improved them. The sorting idea was ripped from Paul Tingey, his PropertySorter class. Globalization was ripped from Globalized Property Grid by Gerd Klevesaat. He, however, used inheritance from GlobalizationObject, which makes the mechanism not so flexible. Plus, his implementation was very slow (especially in combination with sorting), and didn't include Category globalization. The dynamic behaviour was developed by George Soules and me.

Using the code

The example below basically shows most of the possibilities:

using System;
using System.ComponentModel;

using PropertyGridUtils;

namespace MyNameSpace
    class SomeClassWithProperties {
        string lastName = "Zeeuw";
        string occupation = "Software engineer";

        int dynamicProperty = 3;
        string dynamicPropertyDisplayName = "Dynamic property";
        bool dynamicPropertyIsVisible = true;
        bool dynamicPropertyIsReadOnly = false;

        string propertyWithResourcesElseWhere = "Dummy";
        SomeClassWithProperties child;

        // DisplayName and Description are gotten from resource file
        // MyNameSpace.SomeClassWithProperties.resources.
        [GlobalizedProperty(CategoryId = "GlobalCategory")]
        public string LastName {
            get {
                return lastName;

        // DisplayName and Description are gotten from resource file
        // MyNameSpace.SomeClassWithProperties.resources.
        [GlobalizedProperty(CategoryId = "GlobalCategory")]
        public string Occupation {
            get {
                return occupation;

        // Behaviour of this property is partially defined runtime.
        [Description("This property is partially dynamic.")]
        public int DynamicProperty {
            get {
                return dynamicProperty;
            set {
                dynamicProperty = value;

        public void DynamicPropertyAttributesProvider(PropertyAttributes attributes) {
            attributes.DisplayName = dynamicPropertyDisplayName;
            attributes.IsReadOnly = dynamicPropertyIsReadOnly;
            attributes.IsBrowsable = dynamicPropertyIsVisible;

        [DisplayName("Dynamic property display name")]
        public string DynamicPropertyDisplayName {
            get {
                return dynamicPropertyDisplayName;
            set {
                dynamicPropertyDisplayName = value;

        [DisplayName("Dynamic property visible")]
        public bool DynamicPropertyIsVisible {
            get {
                return dynamicPropertyIsVisible;
            set {
                dynamicPropertyIsVisible = value;

        [DisplayName("Dynamic property readonly")]
        public bool DynamicPropertyIsReadOnly {
            get {
                return dynamicPropertyIsReadOnly;
            set {
                dynamicPropertyIsReadOnly = value;

        // DisplayName and Description are gotten from resource file
        // SomeOtherResources.resources
                            BaseName = "SomeOtherResources",
                            DisplayNameId = "Dummy.DisplayName",
                            DescriptionId = "Dummy.Description"
        public string PropertyWithResourcesElseWhere {
            get {
                return propertyWithResourcesElseWhere;

        // Property with sub properties for testing
        // tabbing accross expanded/non expanded items.
        public SomeClassWithProperties Child {
            get {
                if (child == null) {
                    child = new SomeClassWithProperties();
                return child;

Static usage

Property behaviour is defined using the attributes DisplayNameAttribute, DescriptionAttribute, GlobalizedPropertyAttribute, GlobalizedTypeAttribute, and PropertyOrderAttribute.

Usage without resources is simple, users can use the DisplayNameAttribute and DescriptionAttribute to directly set the DisplayName and Description. But when working like this, the properties are not globalized.

Using resource files enables globalization, but is slightly more complicated. By default, resources are gotten from a file namespace.class.resources. This can, if needed, be controlled with the GlobalizedPropertyAttribute or GlobalizedTypeAttribute. The resource for DisplayName is gotten from the ResourceManager from the resource string SomeProperty.DisplayName. Similarly, the Description is gotten from SomeProperty.Description. This can also be controlled through the GlobalizedPropertyAttribute though, so, e.g., description strings can be reused in multiple properties/classes. Category is, by default, gotten from SomeProperty.Category. To reuse a category string in a resource file, you can specify [GlobalizedProperty(CategoryId = "GlobalCategory")] (thanks to Paul Tingey for the idea).

Dynamic usage

It is possible to define a PropertyAttributesProviderAttribute at a property. The method name mentioned there will be called by the PropertiesDeluxeTypeConverter with a PropertyAttributes object as the only parameter. The method can then change all attributes there, like IsBrowsable, IsReadOnly, DisplayName, etc. The PropertyGrid must be refreshed (Refresh()) for the changes to take effect.

Tabbing through properties

To make use of the Tab key feature and globalized tool tips for the tool bar buttons, use CustomPropertyGrid. It also has a property ExpandOnTab which sets whether to expand an expandable item when tab is pressed. Note that pressing the Enter key also achieves that.

Points of interest

If no resource file is there for the neutral culture, globalization is disabled. But still, PropertiesDeluxeTypeConverter can then be used for sorting and setting the DisplayName of properties.

One could set up the resources to, e.g., use only one resource file. There is no protection from name clashes then though. The namespace could be prepended to the resource names, but then the names would get very long.

For adding languages for the tool tips, compile satellite assemblies containing the PropertyGridUtils.CustomPropertyGrid.<language>.resources file (don't forget signing and giving it the correct assembly version, see PropertyGridUtils\compileResources.bat). The assembly must be located in a <language> subdir, like the nl example.

New status bar class (.NET 1.1 only)

I also wrote a small status bar class because the standard .NET 1.1 status bar doesn't allow embedding of controls (the .NET 2.0 StatusStrip is more powerful). It's not much code so it's probably not worth devoting a separate article to it (and there's already one somewhere on CodeProject doing something similar). One feature that is in this version that I like is that both absolute and relative widths can be mixed in the status bar items. E.g., two items can be defined, one of absolute width 50 pixels, relative width 70%, and the other item 200 pixels, relative width 30%. If the total status bar width is 1000 pixels, then 200 + 50 = 250 pixels are fixed. The remaining 750 pixels are divided according to the relative sizes.


  • 7 April 2006, migrated to .NET 2.0 (DisplayNameAttribute is now part of the .NET libraries).
  • 21 June 2005, improved tabbing to go over all expanded items instead of items on one level ( Also added a new status bar class.
  • 19 October 2004, cooperated with George Soules to add dynamic behaviour. (Assembly version is now
  • 12 September 2004, added Tab key feature and globalized tool tips for tool bar buttons.
  • 21 July 2004, first version.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

wout de zeeuw
Software Developer (Senior)
Netherlands Netherlands
Wout works as a freelancer based in the Netherlands. His interests are .NET, 3D, DWG, DXF, OpenGL, Computational Geometry and playing Tank Ball!

One of his latest private projects is a commercial DWG DXF .NET library and small DWG DXF viewing application.

Comments and Discussions

GeneralRe: Licensing? Pin
Steve Maier19-Aug-05 9:56
professionalSteve Maier19-Aug-05 9:56 
GeneralRe: Licensing? Pin
Eugene Polonsky19-Aug-05 9:59
memberEugene Polonsky19-Aug-05 9:59 
GeneralRe: Licensing? Pin
Steve Maier19-Aug-05 10:13
professionalSteve Maier19-Aug-05 10:13 
AnswerRe: Licensing? Pin
wout de zeeuw19-Aug-05 22:30
memberwout de zeeuw19-Aug-05 22:30 
As Steve says. It's all free.
I can give you my bank account nr if you wish to make a donation though Smile | :)


GeneralWorking with mutiples class Pin
CFQüeb10-Jun-05 7:54
memberCFQüeb10-Jun-05 7:54 
GeneralRe: Working with mutiples class Pin
wout de zeeuw10-Jun-05 12:32
memberwout de zeeuw10-Jun-05 12:32 
GeneralChanges to tabbing through properties Pin
DavidMT31-May-05 20:05
memberDavidMT31-May-05 20:05 
GeneralRe: Changes to tabbing through properties Pin
wout de zeeuw21-Jun-05 7:16
memberwout de zeeuw21-Jun-05 7:16 
GeneralSetting column widths Pin
Member 74542029-Mar-05 12:49
memberMember 74542029-Mar-05 12:49 
GeneralRe: Setting column widths Pin
wout de zeeuw31-Mar-05 22:48
memberwout de zeeuw31-Mar-05 22:48 
GeneralRe: Setting column widths Pin
Ryan McFarren20-Sep-05 2:53
memberRyan McFarren20-Sep-05 2:53 
GeneralRe: Setting column widths Pin
wout de zeeuw20-Sep-05 12:38
memberwout de zeeuw20-Sep-05 12:38 
GeneralLocalizable DataSets Pin
pinx5-Nov-04 9:01
memberpinx5-Nov-04 9:01 
GeneralReadOnly and Hide Pin
George Soules8-Oct-04 2:01
memberGeorge Soules8-Oct-04 2:01 
GeneralRe: ReadOnly and Hide Pin
George Soules11-Oct-04 11:02
memberGeorge Soules11-Oct-04 11:02 
GeneralRe: ReadOnly and Hide Pin
wout de zeeuw19-Oct-04 23:11
memberwout de zeeuw19-Oct-04 23:11 
GeneralRe: ReadOnly and Hide Pin
tonyt17-Dec-05 23:47
membertonyt17-Dec-05 23:47 
GeneralRe: ReadOnly and Hide Pin
wout de zeeuw18-Dec-05 0:56
memberwout de zeeuw18-Dec-05 0:56 
GeneralRe: ReadOnly and Hide Pin
George Soules19-Dec-05 1:37
memberGeorge Soules19-Dec-05 1:37 
GeneralGlobalization of the tooltips Pin
aagirre9-Sep-04 20:16
memberaagirre9-Sep-04 20:16 
GeneralRe: Globalization of the tooltips Pin
wout de zeeuw12-Sep-04 9:55
memberwout de zeeuw12-Sep-04 9:55 
GeneralRe: Globalization of the tooltips Pin
aagirre12-Sep-04 23:49
memberaagirre12-Sep-04 23:49 
GeneralRe: Globalization of the tooltips Pin
aagirre13-Sep-04 21:07
memberaagirre13-Sep-04 21:07 
GeneralRe: Globalization of the tooltips Pin
wout de zeeuw14-Sep-04 0:53
memberwout de zeeuw14-Sep-04 0:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Posted 7 Jan 2016


148 bookmarked