Why doesn’t my TypeConverter get called?


Consider the following code:



public class MyControl : Control {




[TypeConverter(typeof(SomePropertyConverter))]
public Foo SomeProperty {
   get
{ … }
}


}



[TypeConverter(typeof(FooConverter))]
public class Foo
{


   …
}


Now here are a couple of questions:




  1. Let’s say both SomePropertyConverter and FooConverter implement conversion to and from String, given an instance of Foo. If I drop MyControl on a Form designer and try to edit SomeProperty in the property grid, which TypeConverter will get called?


  2. Let’s say both SomePropertyConverter and FooConverter implement conversion to InstanceDescriptor, given an instance of Foo. The intention is to control how an object of type Foo gets serialized to code. Which TypeConverter will get called?

The answer to question 1 is SomePropertyConverter. This is because the property grid will query the TypeConverter off the PropertyDescriptor for SomeProperty. The converter look up for properties gives precedence to TypeConverters attached to the property itself over the TypeConverter attached to the object or type. This allows a class like MyControl to control the behavior of the type Foo in the property grid, as related to SomeProperty.


What about question 2? One might expect the behavior to be consistent with 1. Well, no, it is not – the correct answer is FooConverter. This is because the serialization code queries the TypeConverter off the object or type itself, not off the PropertyDescriptor.


It is not immediately obvious why this is the case, and many people wonder if this ‘inconsistency’ is a bug in the component model. No, it is actually by design. To understand this, let’s assume for a moment that the serializer did query the TypeConverter off the PropertyDescriptor. What would happen if the same instance of Foo is assigned to several different properties, each of which had their own TypeConverters specified? How then would the serializer know which TypeConverter to pick? After all, the object itself can be serialized in only one way. It is to avoid such ambiguities that type serializers ignore TypeConverters (and certain other metadata) attached to properties in determining how to serialize objects. This is also why the DesignerSerializerAttribute can only be applied to types, not to properties.


Note that this doesn’t mean MyControl doesn’t have a say in the serialization of SomeProperty. As I have explained in an earlier post, there are several ways it can control how the property itself is serialized. Note that there is a distinction between type serializers and member serializers. This distinction is made clear in Whidbey by bifurcating the CodeDomSerializer class hierarchy into two base classes, called TypeCodeDomSerializer and MemberCodeDomSerializer, both of which derive from a common base class called CodeDomSerializerBase.


Comments (6)

  1. Brandon Bloom says:

    I wrote my own TypeConverter for Microsoft.DirectX.Vector3 based on the System.Drawing.PointConverter class. I was banging my head against the wall trying to figure out why it still generated this code:

    this.blah1.Position = ((Microsoft.DirectX.Vector3)(resources.GetObject("blah1.Position")));

    Instead of

    this.blah1.Position = new Microsoft.DirectX.Vector3(0.0f, 10.0f, -5.0f);

    that is… until I read this blog post.

    Now I am stumped. How would I go about getting this to work?

  2. rprabhu says:

    You could derive from the class in question and attach your TypeConverter to it.

    If you are using Whidbey, you have another option – you could use the TypeDescriptor.AddAttributes() method to specify your TypeConverter directly on the type/instance.

  3. Brandon Bloom says:

    I am using Whidbey, and the TypeDescriptor.AddAttributes worked like a charm!

    Thanks a bunch!

    For now I just tossed the AddAttributes at the beginning of main, but where would you recommend I perform global modifications to the attributes of types?

  4. rprabhu says:

    It really depends on your scenario and the attributes you are trying to modify – there isn’t a general recommendation. Doing it in Main is fine – another option would be to do it the first time you access the type in question.

  5. Debasish says:

    Type Coverter is not working when trying to access from VISIO Com addin.Requiremnt on right-mouse click on any visio shape one property grid will open with the properties of that shape.Among those properties one class is working as a nested property so required TypeConverter class. Same code is working on any .NET windows application but on Visio Com add-in TypeConverter is ignored. Any Solution? Plz Help. Mail to "debasish.paul@cognizant.com"

  6. rprabhu says:

    Debasish: Sorry, no idea about this problem. I would try posting the question on one of the MSDN forums or contact Microsoft product support.