Click here to Skip to main content
15,867,453 members
Articles / Programming Languages / C#

Making a PropertyGrid ReadOnly

Rate me:
Please Sign up or sign in to vote.
4.50/5 (9 votes)
6 Jul 2010CPOL6 min read 69.9K   1.7K   10   28
The System.Windows.Forms.PropertyGrid does not support displaying the selected objects as read only. This article describes the way to do it.

Introduction

The PropertyGrid is one of the most useful controls provided in System.Windows.Forms namespace. However, one important feature missing in it is the ability to display the selected object in a read only format. This article proposes a method to achieve this by the means of a control that inherits PropertyGrid and wraps the selected object in a custom wrapper to bring about the read only effect.

Understanding the Terms Used in this Article

Throughout this article, you will come across terms like PropertyGrid, TypeDescriptor, ICustomTypeDescriptor, PropertyDescriptor, etc. If you feel comfortable with these terms and understand their roles, it would be easier to understand the article. If not, no worries. You may directly skip to the how to use section. The knowledge of these terms or their working is not necessary to be able to use the solution. The attached binaries include the XML documentation to make it easier to use the properties and methods of the proposed control.

Motivation

Nearly two years ago, while working on a designer I had faced a situation where the PropertyGrid was expected to display the selected object as read only in certain situations. But the control provided by the framework has no provision for the same. So, while searching for the possible solutions, I came across a lot of forums where others needed a similar behavior but no elegant solution was proposed. The most widely used workarounds were:

  1. Simply disabling the control when the read only behavior was needed

    Problems: Disabling the control is not only a lazy substitute, but also a visually unpleasant one. When the control is disabled, it loses its ability to scroll, thereby rendering it pretty useless when it comes to browsing through the properties. It also makes the grids un-expandable, so viewing the child properties is impossible.

  2. Implementing ICustomTypeDescriptor for the classes whose objects need to be displayed as selected object

    Problems: Implementing ICustomTypeDescriptor does empower the type to tailor its properties and manipulate their attributes. However this ability is restricted to the implementing class and has no power over the child properties. And it is not always possible to implement ICustomTypeDescriptor for all the classes that may make up the properties of the root object, because they may be a part of the framework's classes. Thus this does not provide a fool proof and complete solution. Some also propose to disable the ability to expand the child properties. But this, again, makes browsing the properties a big pain.

So, after playing around with PropertyGrid, TypeConverters, TypeDescriptors, etc. I had discovered the following solution then. And recently I realized that this, or a similar solution, was not yet available to everyone (at least my search for it proved futile) I decided to publish it here.

Proposed Solution

The solution proposed in this article involves the use of a new control called RPropertyGrid that inherits from PropertyGrid and has a property called ReadOnly which can be used to make the selected object read only.

Internally, when the ReadOnly property is set to true the control wraps the selected objects by instances of a custom class called the ReadOnlyWrapper, which makes the object behave as if they were read only.

Behind the Scene

When the selected object is wrapped by the ReadOnlyWrapper, the following components come into play.

ReadOnlyWrapper: This is the class where the process of making the object seem read only happens. It implements ICustomTypeDescriptor, but most of the implemented methods return the values obtained by calling their counterparts provided by the TypeDescriptor class on the wrapped object. The only method that does not do this is the GetProperties method which in turn wraps the original properties (instances of PropertyDescriptor) by instances of ReadOnlyPropertyDescriptor.

ReadOnlyPropertyDescriptor: This is the class that serves as a proxy property descriptor and its ReadOnly property always returns true. This makes them appear as read only in the PropertyGrid. The other two aberrations in this class are in the form of the property Converter and the method GetEditor which always return instances of ReadOnlyConverter and UITypeEditor respectively.

ReadOnlyConverter: This is the class that derives from TypeConverter and acts on behalf of the original converter of the wrapped object. In most cases, it simply returns the actual values obtained by using the counterpart methods of the original converter. However, the GetProperties method, again, is the only point where the behavior changes. In the custom implementation of this method, instead of returning the original PropertyDescriptor of the properties, they are wrapped in instances of ReadOnlyPropertyDescriptor, thus making the child properties read only too.

Since ReadOnlyPropertyDescriptor uses ReadOnlyConverter and vice versa, all the properties of the root object and the subsequent properties of its child properties are made read only. This "symbiotic" mechanism forms the core of the idea. Also, since all the wrapping and unwrapping happens at the PropertyDescriptor and TypeConverter levels, it makes no difference if the wrapped object is a custom object or one that instantiates some built-in class.

How to Use RPropertyGrid

There is no need to make any change in your existing components to be able to use the given solution. Your classes need not implement any special interface or derive from any special class.

RPropertyGrid derives from PropertyGrid, so it can simply replace your existing control without demanding any change in the way selected objects are set. Here is an example (with your original code shown in comments).

C#
//PropertyGrid propertyGrid = new PropertyGrid(); 
RPropertyGrid propertyGrid = new RPropertyGrid();
propertyGrid.SelectedObject = value;   

Moreover, it provides three new properties which have the following use:

  • ReadOnly: Property that lets you set (and, of course, get) the selected objects as read only. Everything that needs to be done is internally handled.
  • OriginalSelectedObject: Property that lets you get the original selected object, in case you need to retrieve the actual object that was used as the selected object (and not the custom wrapper's instance).
  • OriginalSelectedObjects: Property that lets you get the original selected objects, in case you need to retrieve the actual objects that were used as the selected objects (and not the custom wrapper's instances).

Limitations

When the ReadOnly property is set to true, the UITypeEditors of the properties are stopped from being shown. Generally this is not a problem because properties with a UITypeEditor typically have a TypeConverter associated with them that show their state well enough. However, in rare cases where an object can only be described by the means of an editor (e.g. a pop-up editor that could show an image for a property of type Image), this limitation would apply.

Just a Side Note

I intend to add some more controls to this assembly in the future, and hence the audacious name. Please excuse me for it!

History

  • June 28, 2010: Article submitted
  • July 7, 2010: Made correction to stop the extra firing of 'SelectedObjectsChanged' event

License

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


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
David Catriel28-Apr-11 15:22
David Catriel28-Apr-11 15:22 
GeneralRe: My vote of 5 Pin
rajeev51128-Apr-11 16:42
rajeev51128-Apr-11 16:42 

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.