Click here to Skip to main content
Click here to Skip to main content

PropertyGrid utilities

By , 7 Apr 2006
Rate this:
Please Sign up or sign in to vote.

Introduction

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

Features:

  • 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.

Background

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
{
    [TypeConverter(typeof(PropertiesDeluxeTypeConverter))]
    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.
        [PropertyOrder(0)]
        [GlobalizedProperty(CategoryId = "GlobalCategory")]
        public string LastName {
            get {
                return lastName;
            }
        }

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

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

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

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

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

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

        // DisplayName and Description are gotten from resource file
        // SomeOtherResources.resources
        [PropertyOrder(6)]
        [GlobalizedProperty(
                            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.
        [PropertyOrder(7)]
        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.

History

  • 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 (1.0.0.3). Also added a new status bar class.
  • 19 October 2004, cooperated with George Soules to add dynamic behaviour. (Assembly version is now 1.0.0.2.)
  • 12 September 2004, added Tab key feature and globalized tool tips for tool bar buttons.
  • 21 July 2004, first version.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

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.
 
Read the Wout Ware Blog for blog posts where Wout shares his experiences with .NET technology.

Comments and Discussions

 
QuestionLicense PinmemberBMW74012-Jul-12 23:11 
GeneralMy vote of 5 Pinmembercdinten11-Jun-12 3:10 
nice work!
GeneralRe: My vote of 5 Pinmemberwout de zeeuw19-Jun-12 4:31 
GeneralFinally PinmemberLW0027-Jan-10 4:40 
GeneralRe: Finally Pinmemberwout de zeeuw27-Jan-10 5:05 
GeneralTab! Tab! Tab! PinmemberRyan McFarren20-Mar-09 10:48 
GeneralRe: Tab! Tab! Tab! Pinmemberwout de zeeuw20-Mar-09 17:42 
GeneralNew solution with greater flexibility PinmemberMizan Rahman22-Feb-09 4:12 
QuestionHow do I use the Enter key for tabbing through items. PinmemberP.Joshi16-May-08 7:26 
AnswerRe: How do I use the Enter key for tabbing through items. Pinmemberxiwang10-Oct-08 0:42 
GeneralRe: How do I use the Enter key for tabbing through items. PinmemberP.Joshi13-Oct-08 4:26 
GeneralDisplay collections as child nodes PinmemberLen202025-Feb-08 9:53 
GeneralFantastic PinmemberAngelus1234519-Jul-07 1:23 
GeneralRe: Fantastic Pinmemberwout de zeeuw19-Jul-07 1:59 
GeneralGreat Pinmembermileni21-Mar-07 23:31 
GeneralRe: Great Pinmemberwout de zeeuw30-May-07 3:10 
GeneralRemoving Properties inherited from PictureBox Pinmemberkhoonseng13-Dec-06 19:56 
GeneralProperty sorting in VS2005 c++ Pinmemberkhoonseng13-Dec-06 19:43 
GeneralRe: Property sorting in VS2005 c++ Pinmemberelfi1221-Aug-07 5:23 
GeneralProperty sorting not working with devexpress propertygrid Pinmemberpraveenqwe15-Nov-06 0:34 
GeneralAttibute fuction in other class Pinmemberpraveenqwe6-Nov-06 17:46 
GeneralRe: Attibute fuction in other class Pinmemberwout de zeeuw7-Nov-06 0:48 
GeneralGreat! PinmemberQuerulant26-Jul-06 10:57 
GeneralRe: Great! Pinmemberwout de zeeuw20-Aug-06 0:38 
GeneralCategory Localisation doesn't work when using multiple SelectedObjects PinmemberJerleth.15-May-06 0:53 
GeneralRe: Category Localisation doesn't work when using multiple SelectedObjects Pinmemberwout de zeeuw15-May-06 7:07 
GeneralRe: Category Localisation doesn't work when using multiple SelectedObjects PinmemberStuart Wells4-Jul-06 5:24 
AnswerSolution: Category Localisation doesn't work when using multiple SelectedObjects PinmemberNiels.Bos9-May-07 2:44 
GeneralRe: Solution: Category Localisation doesn't work when using multiple SelectedObjects PinmemberLen202025-Feb-08 9:48 
GeneralLocalize the child property's names in PropertyGrid. Pinmemberkrzychub7-Jan-06 6:55 
GeneralRe: Localize the child property's names in PropertyGrid. Pinmemberwout de zeeuw7-Jan-06 7:41 
GeneralRe: Localize the child property's names in PropertyGrid. Pinmemberkrzychub7-Jan-06 9:09 
GeneralRe: Localize the child property's names in PropertyGrid. Pinmemberwout de zeeuw7-Jan-06 23:42 
QuestionHow to control the height of the PropertyGrid comment area Pinmemberdsk303719-Dec-05 9:12 
AnswerRe: How to control the height of the PropertyGrid comment area Pinmembergedri25-Dec-06 6:27 
Generalto show/replace it in the Properties View Pinmembergankh17-Dec-05 15:43 
GeneralRe: to show/replace it in the Properties View Pinmemberwout de zeeuw17-Dec-05 22:31 
GeneralRe: to show/replace it in the Properties View Pinmembergankh23-Dec-05 15:45 
GeneralPerformance PinmemberTuakisan5-Dec-05 19:47 
GeneralPerformance PinmemberTuakisan15-Dec-05 23:20 
GeneralRe: Performance Pinmemberwout de zeeuw16-Dec-05 8:44 
QuestionLicensing? PinmemberEugene Polonsky19-Aug-05 8:36 
AnswerRe: Licensing? PinmemberSteve Maier19-Aug-05 9:13 
GeneralRe: Licensing? PinmemberEugene Polonsky19-Aug-05 9:47 
GeneralRe: Licensing? PinmemberSteve Maier19-Aug-05 9:56 
GeneralRe: Licensing? PinmemberEugene Polonsky19-Aug-05 9:59 
GeneralRe: Licensing? PinmemberSteve Maier19-Aug-05 10:13 
AnswerRe: Licensing? Pinmemberwout de zeeuw19-Aug-05 22:30 
GeneralWorking with mutiples class PinmemberCFQüeb10-Jun-05 7:54 
GeneralRe: Working with mutiples class Pinmemberwout de zeeuw10-Jun-05 12:32 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140415.2 | Last Updated 7 Apr 2006
Article Copyright 2004 by wout de zeeuw
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid