Click to Rate and Give Feedback
Related Articles

In this column, the author lays out some guiding principles that you should follow when working with the ASP.NET MVC framework.

Scott Allen

MSDN Magazine July 2009

...

Read more!

We demonstrate creating a peer-to-peer processing platform where multiple players function together for a common purpose: getting your work done.

Matt Neely

MSDN Magazine June 2009

...

Read more!

This column shows you how to secure the .NET Services Bus and also provides some helper classes and utilities to automate many of the details.

Juval Lowy

MSDN Magazine July 2009

...

Read more!

Here the author dissects the ASP.NET MVC framework and looks at how controllers work. He then explains how the framework interacts with your controllers and how you can influence those interactions.

Scott Allen

MSDN Magazine May 2009

...

Read more!

In this month's column, we’ll explore the pros and cons of both ASP.NET Web Forms and ASP.NET MVC.

Dino Esposito

MSDN Magazine July 2009

...

Read more!

Also by this Author

This month Stephen Toub answers questions pertaining to the Windows Vista Restart Manager API and generic method compilation.

Stephen Toub

MSDN Magazine April 2007

...

Read more!

Stephen Toub gets nostalgic as he prepares to leave MSDN Magazine.

Stephen Toub

MSDN Magazine August 2007

...

Read more!

We take a look at planned support for parallel programming for both managed and native code in the next version of Visual Studio.

Stephen Toub and Hazim Shafi

MSDN Magazine October 2008

...

Read more!

Many developers who use the Microsoft .NET Framework think that application type is tied to the libraries that can be used in that application. Stephen Toub clarifies.

Stephen Toub

MSDN Magazine June 2007

...

Read more!

In this month’s installment, Stephen Toub examines some techniques for enforcing dependencies in the running order of asynchronous operations and builds a DependencyManagement class to help.

Stephen Toub

MSDN Magazine April 2009

...

Read more!

Popular Articles

C# allows developers to embed XML comments into their source files-a useful facility, especially when more than one programmer is working on the same code. The C# parser can expand these XML tags to provide additional information and export them to an external document for further processing. This article shows how to use XML comments and explains the relevant tags. The author demonstrates how to set up your project to export your XML comments into convenient documentation for the benefit of other developers. He also shows how to use comments ...

Read more!

Paul DiLascia

MSDN Magazine August 2002

...

Read more!

The MVP pattern helps you separate your logic and keep your UI layer free of clutter. This month learn how.

Jean-Paul Boodhoo

MSDN Magazine August 2006

...

Read more!

Now you can perform efficient, sophisticated text analysis using regular expressions in SQL Server 2005.

David Banister

MSDN Magazine February 2007

...

Read more!

When incorporating the ASP.NET DataGrid control into your Web apps, common operations such as paging, sorting, editing, and deleting data require more effort than you might like to expend. But all that is about to change. The GridView control--the successor to the DataGrid-- extends the DataGrid's functionality it in a number of ways. First, it fully supports data source components and can automatically handle data operations, such as paging, sorting, and editing, as long as its bound data source object supports these capabilities. In addition, ...

Read more!

.NET Matters
ICustomTypeDescriptor, Part 1
Stephen Toub

Code download available at: NETMatters0504.exe (163 KB)
Browse the Code Online

Q I write a lot of one-off utilities for personal use, and since they don't require any sophisticated user interfaces, I often use a System.Windows.Forms.PropertyGrid bound to a settings class in order to allow the user to configure a tool's operations. Unfortunately, sometimes I don't write these settings classes, and often they've been constructed in a way that's incompatible with the PropertyGrid. For example, I often bind to client proxy classes created by wsdl.exe in order to make Web service requests from my tool. The problem is that these proxy classes expose fields rather than properties. Thus, none of these configuration settings shows up in the PropertyGrid. Short of manually going in and changing each field to a property each time these proxy classes are autogenerated, is there any way to get the behavior I need?
Q I write a lot of one-off utilities for personal use, and since they don't require any sophisticated user interfaces, I often use a System.Windows.Forms.PropertyGrid bound to a settings class in order to allow the user to configure a tool's operations. Unfortunately, sometimes I don't write these settings classes, and often they've been constructed in a way that's incompatible with the PropertyGrid. For example, I often bind to client proxy classes created by wsdl.exe in order to make Web service requests from my tool. The problem is that these proxy classes expose fields rather than properties. Thus, none of these configuration settings shows up in the PropertyGrid. Short of manually going in and changing each field to a property each time these proxy classes are autogenerated, is there any way to get the behavior I need?

A It sounds like you're using the Microsoft® .NET Framework 1.x, given your description of wsdl.exe and the proxy classes it generates. In the .NET Framework 2.0, the default operation of wsdl.exe is to generate public properties that wrap private fields, rather than the only mode of operation in version 1.x, which is to generate public fields. So, using proxy classes as you describe will just start working for you when you start using the .NET Framework 2.0. But obviously that doesn't solve the larger problem, nor does it work for you in the .NET Framework 1.x.
A It sounds like you're using the Microsoft® .NET Framework 1.x, given your description of wsdl.exe and the proxy classes it generates. In the .NET Framework 2.0, the default operation of wsdl.exe is to generate public properties that wrap private fields, rather than the only mode of operation in version 1.x, which is to generate public fields. So, using proxy classes as you describe will just start working for you when you start using the .NET Framework 2.0. But obviously that doesn't solve the larger problem, nor does it work for you in the .NET Framework 1.x.
If the PropertyGrid bound to your types used only reflection to examine a type's metadata, you'd be out of luck, and there'd be no way to accomplish what you're trying to do (short of some hackish and non-user-friendly workarounds, one of which might be dynamic code generation). Luckily, it doesn't. PropertyGrid relies on special types from the System.ComponentModel namespace to provide it with information about the objects to which it is bound.
One such type, System.ComponentModel.TypeDescriptor, is used to retrieve information about the properties and events a particular component exposes. In the most general case, TypeDescriptor simply uses reflection to return a System.ComponentModel.PropertyDescriptor for each public instance property found on the type. However, other factors influence exactly which PropertyDescriptors are returned. For example, if the object being described is a component and is associated with a Container that also contains extender provider components (such as System.Windows.Forms.ToolTip) to provide additional properties to this object, TypeDescriptor.GetProperties will return a System.ComponentModel.PropertyDescriptorCollection that contains descriptors for these extender properties in addition to the ones found through reflection and the type's metadata (for more information on provider controls, see the Cutting Edge column in the November 2003 issue of MSDN®Magazine).
Before going straight to the metadata to get property information, TypeDescriptor first checks to see if the type being examined implements the System.ComponentModel.ICustomTypeDescriptor interface. If it does, and if some other conditions are met (to be discussed shortly), rather than using the metadata to get property information, TypeDescriptor will simply ask the object (through its ICustomTypeDescriptor.GetProperties method) which properties it supports. This gives the object itself a chance to hand back a PropertyDescriptorCollection containing exactly the properties it wants displayed in the PropertyGrid. That's good news for you, because it means your type can fool the PropertyGrid into thinking your type has properties it doesn't really have. More specifically, you can convince the PropertyGrid that each of your fields is actually a property. To do so, you need to create a custom PropertyDescriptor for each field you want displayed—in this case, all public fields.
PropertyDescriptor is an abstract class that derives from another abstract class, MemberDescriptor. You can think of MemberDescriptor as providing the basic information for each property, specifically its name and any System.Attribute instances associated with that property. It also provides some useful helper functions that pull out information from those attributes (for example, MemberDescriptor.Category looks to see if one of the attributes is a CategoryAttribute, and if it finds one, returns that attribute's Category string value). PropertyDescriptor adds functionality related to changing a property's value and determining when that value has changed. So, for example, it exposes GetValue and SetValue abstract methods as well as an OnValueChanged method, which will notify any listeners that this property's value has changed. Tricky naming, huh?
To create a PropertyDescriptor for each field, you first need to create a custom class that derives from PropertyDescriptor. An example of one viable class for your purposes is shown in Figure 1. This FieldPropertyDescriptor class wraps a System.Reflection.FieldInfo class describing a field on a type. The constructor initializes the base MemberDescriptor with the name of the field as the property name and the field's attributes as the property's attributes. (The PropertyGrid uses the attributes from the PropertyDescriptor to determine important display settings, such as name, category, description, and even which UITypeEditor to use.)
public class FieldPropertyDescriptor : PropertyDescriptor
{
    private FieldInfo _field;

    public FieldPropertyDescriptor(FieldInfo field) : base(field.Name,
        (Attribute[])field.GetCustomAttributes(typeof(Attribute), true))
    {
        _field = field;
    }

    public FieldInfo Field { get { return _field; } }
    
    public override bool Equals(object obj)
    {
        FieldPropertyDescriptor other = obj as FieldPropertyDescriptor;
        return other != null && other._field.Equals(_field);
    }

    public override int GetHashCode() { return _field.GetHashCode(); }

    public override bool IsReadOnly { get { return false; } }

    public override void ResetValue(object component) {}

    public override bool CanResetValue(object component) { return false;}

    public override bool ShouldSerializeValue(object component) 
    { 
        return true; 
    }

    public override Type ComponentType 
    {
        get { return _field.DeclaringType; } 
    }

    public override Type PropertyType { get { return _field.FieldType; }}

    public override object GetValue(object component) 
    { 
        return _field.GetValue(component); 
    }

    public override void SetValue(object component, object value) 
    {
        _field.SetValue(component, value); 
        OnValueChanged(component, EventArgs.Empty);
    }
}
The rest of the class is fairly self-explanatory. GetValue and SetValue use reflection and the stored FieldInfo to access and modify the underlying field's value. PropertyType returns the field's type. And the Equals method compares the stored FieldInfo objects rather than the FieldPropertyDescriptors. Note that any type that overrides Object.Equals should also override Object.GetHashCode, as I've done here.
With FieldPropertyDescriptor in hand, you now need to provide instances of it back to the PropertyGrid. As noted earlier, this can be accomplished by having your type implement the ICustomTypeDescriptor interface, paying particular attention to the GetProperties method. Unfortunately, yes, this requires you to modify your type. However, I'll show you how to cut down on the number of changes you need to make to each type by putting all of this functionality into a common base class. Then, all you need to do to use this functionality with your field-exposing type is to derive from this new base class; no changes to your type's members will be necessary.
Figure 2 shows just such a base class. The most important method is GetProperties, which returns the PropertyDescriptionCollection that'll be used by callers to determine which properties this instance supports. The core of it, ignoring for a moment all of the extra boilerplate, is implemented as follows:
PropertyDescriptorCollection props = 
    new PropertyDescriptorCollection(null);
foreach(PropertyDescriptor prop in 
    TypeDescriptor.GetProperties(this, attributes, true))
        props.Add(prop);
foreach (FieldInfo field in GetType().GetFields())
    props.Add(new FieldPropertyDescriptor(field));
return props;
public abstract class FieldsToPropertiesTypeDescriptor : 
    ICustomTypeDescriptor
{
    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
    {
        return this;
    }

    AttributeCollection ICustomTypeDescriptor.GetAttributes()
    {
        return TypeDescriptor.GetAttributes(this, true);
    }

    string ICustomTypeDescriptor.GetClassName()
    {
        return TypeDescriptor.GetClassName(this, true);
    }

    ...

    private PropertyDescriptorCollection _propCache;
    private FilterCache _filterCache;

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
    {
        return ((ICustomTypeDescriptor)this).GetProperties(null);
    }

    PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(
        Attribute[] attributes)
    {
        bool filtering = (attributes != null && attributes.Length > 0);
        PropertyDescriptorCollection props = _propCache;
        FilterCache cache = _filterCache;

        // Use a cached version if possible
        if (filtering && cache != null && cache.IsValid(attributes)) 
            return cache.FilteredProperties;
        else if (!filtering && props != null) 
            return props;

        // Create the property collection and filter
        props = new PropertyDescriptorCollection(null);
        foreach(PropertyDescriptor prop in 
            TypeDescriptor.GetProperties(
            this, attributes, true)) 
        {
            props.Add(prop);
        }
        foreach (FieldInfo field in this.GetType().GetFields())
        {
            FieldPropertyDescriptor fieldDesc = 
                new FieldPropertyDescriptor(field);
            if (!filtering ||  
                fieldDesc.Attributes.Contains(attributes)) 
                props.Add(fieldDesc);
        }

        // Store the computed properties
        if (filtering) 
        {
            cache = new FilterCache();
            cache.Attributes = attributes;
            cache.FilteredProperties = props;
            _filterCache = cache;
        } 
        else _propCache = props;

        return props;
    }

    private class FilterCache
    {
        public Attribute[] Attributes;
        public PropertyDescriptorCollection FilteredProperties;
        public bool IsValid(Attribute[] other)
        {
            if (other == null || Attributes == null) return false;

            if (Attributes.Length != other.Length) return false;

            for (int i = 0; i < other.Length; i++)
            {
                if (!Attributes[i].Match(other[i])) return false;
            }

            return true;
        }
    }
}
The code first gets the collection of descriptors for the actual properties defined on the type with a call to TypeDescriptor.GetProperties. The collection returned will also include any properties inserted by extender provider components. (You'll notice, too, that the third argument to this call, noCustomTypeDesc, is true, which tells TypeDescriptor not to use the instance's ICustomTypeDescriptor implementation. Passing in a value of false here would be fatal, as it would result in infinite recursion and eventually a StackOverflowException as TypeDescriptor proceeded to call into your GetProperties implementation again and again and again.) All of these base descriptors are copied into a new collection. The code then loops through each of the public instance fields on the type and creates a FieldPropertyDescriptor for each, which are promptly added to that new collection. When all of the fields have been wrapped, the collection is returned.
Of course, you'll notice that there's more to my implementation of GetProperties than what I've just described. What I've outlined will be correct functionally, but it won't perform as it otherwise could. Specifically, the resulting PropertyDescriptorCollection could be cached such that future calls to this method could simply return the cached collection rather than recomputing it. However, you have to be careful with how you cache, since TypeDescriptor.GetProperties filters what properties are returned based on the attributes that are passed to the method (only properties that are attributed with one of the specified attributes, either explicitly or by default, are returned). Since I'm augmenting the results of calling to TypeDescriptor.GetProperties in my implementation of ICustomTypeDescriptor.GetProperties, and since TypeDescriptor.GetProperties will filter results, the set to be returned from my implementation must be recomputed based on a different set of attribute filters than were used originally.
To compensate for this, I maintain multiple cached property sets. First, I cache the properties to be used when no attributes are specified as a filter (in other words, the full list of properties). Second, I cache the last property set computed based on the last attribute filter specified, which is also cached. This way, I only have to compute the full set of properties once, and if the same attribute filter is used multiple times in a row, I likewise only have to compute it once.
As an aside, note that in the .NET Framework 1.x filtering in this situation is strictly optional, as TypeDescriptor.GetProperties will filter the property collection before returning it to the caller. If the creation of a custom property descriptor is expensive, you'll want to filter as much as possible before creating the descriptor. In the .NET Framework 2.0 Beta 1, only in certain scenarios (including, for backward compatibility, the scenarios available in the .NET Framework 1.x) will TypeDescriptor perform this filtering for you. More on this next month.
The rest of the FieldsToPropertiesTypeDescriptor class is boilerplate. GetPropertyOwner returns a reference to "this", since the type to be described is deriving from this class (FieldsToPropertiesTypeDescriptor), and it "owns" all of the properties being returned. Almost every other method then delegates to the appropriate method on TypeDescriptor, letting that method do all the heavy lifting (again, with the noCustomTypeDesc parameter set to true).
You can now give this solution a try. Assuming you have a type that looks something like the following
public class Person 
{
    public string Name;
    public int Age;
    public string Hobbies;
}
you can simply modify it to use this new base class as follows:
public class Person : FieldsToPropertiesTypeDescriptor
{
    public string Name;
    public int Age;
    public string Hobbies;
}
And, poof, PropertyGrid will show all of your fields in the grid. This is made possible by the process I've described up to this point, outlined in Figure 3.
Figure 3 Using ICustomTypeDescriptor in the .NET Framework 1.x 
Of course, this isn't quite what you asked for. While this requires minimal modifications to your type, you didn't want to have to change your type at all. Unfortunately, in the .NET Framework 1.x, in order for TypeDescriptor to give back custom properties for a type, that type must implement ICustomTypeDescriptor.
There is a slight variation to this solution that might work for you, however. You can modify the FieldsToPropertiesTypeDescriptor class to be a proxy class rather than an abstract base class for the type in question. This would result in a class that looks similar to the code shown in Figure 4. Here I've renamed FieldsToPropertiesTypeDescriptor to be FieldsToPropertiesProxyTypeDescriptor, removed the abstract modifier, and added a constructor and a private object member variable. The constructor accepts as a parameter the target object that you would have otherwise set as the SelectObject for the PropertyGrid. This object is stored internally to the _target member, which is then used everywhere that the "this" reference was used in Figure 2. Any requests for metadata information about this proxy custom type descriptor will then actually return information about the target object. This allows you to keep your original type unmodified, writing code like the following to show the object in the property grid:
propertyGrid.SelectedObject = 
    new FieldsToPropertiesProxyTypeDescriptor(person);
The solution discussed in this column is useful for more than just working with the PropertyGrid. In fact, another application of descriptors is used much more frequently: ASP.NET data binding. The System.Web.UI.DataBinder class is used heavily in applications that implement data binding. According to the documentation, the DataBinder.Eval method "uses reflection to parse and evaluate a data binding expression against an object at run time." More specifically, however, it uses property descriptors rather than directly using the System.Reflection namespace. DataBinder.Eval calls DataBinder.GetPropertyValue, which is implemented approximately as follows:
public static object GetPropertyValue(object container, string propName)
{
    ...
    PropertyDescriptor propDesc = TypeDescriptor.GetProperties(
        container).Find(propName, true);
    if (propDesc == null) throw new HttpException(...);
    return propDesc.GetValue(container);
}
Thus, you can use the FieldsToPropertiesTypeDescriptor or FieldsToPropertiesProxyTypeDescriptor classes described in this column to allow ASP.NET data binding to work with fields in addition to with properties.
public class FieldsToPropertiesProxyTypeDescriptor : 
    ICustomTypeDescriptor
{
    private object _target; // object to be described

    public FieldsToPropertiesProxyTypeDescriptor(object target)
    {
        if (target == null) throw new ArgumentNullException("target");
        _target = target;
    }

    object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd)
    {
        return _target; // properties belong to the target object
    }

    AttributeCollection ICustomTypeDescriptor.GetAttributes()
    {
        // Gets the attributes of the target object
        return TypeDescriptor.GetAttributes(_target, true);
    }

    string ICustomTypeDescriptor.GetClassName()
    {
        // Gets the class name of the target object
        return TypeDescriptor.GetClassName(_target, true);
    }

    ... // the rest of the class is the same as
        // FieldsToPropertiesTypeDescriptor except using
        // "_target" instead of "this"
}
Next time in this column, I'll continue this discussion of property descriptors, focusing on the .NET Framework 2.0, specifically on how the new TypeDescriptionProvider infrastructure dramatically improves the situation.

Send your questions and comments to  netqa@microsoft.com.


Stephen Toub is the Technical Editor for MSDN Magazine.

Page view tracker