Design-Time Integration—Custom Type Code Serialization with TypeConverters

Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio


Jump to: navigation, search
CSharp-Online.NET:Articles
C# Articles

Design-Time Integration of Windows Forms Components

© 2004 Chris Sells

Custom Type Code Serialization with TypeConverters

Although the Hand type now plays nicely with the Property Browser, it doesn't yet play nicely with code serialization. In fact, at this point it's not being serialized to InitializeComponent at all. To enable serialization of properties exposing complex types, you must expose a public ShouldSerialize<PropertyName> method that returns a Boolean:

public class ClockControl : Control {
  public Hand SecondHand { ... }
  bool ShouldSerializeSecondHand() {
   // Only serialize nondefault values
   return(
     (secondHand.Color != Color.Red) 
     || (secondHand.Width != 1) );
     }
   ...
   }

Internally, the Designer looks for a method named ShouldSerialize <PropertyName> to ask whether the property should be serialized. From the Designer's point of view, it doesn't matter whether your ShouldSerialize<PropertyName> is public or private, but choosing private removes it from client visibility.

To programmatically implement the Property Browser reset functionality, you use the Reset<PropertyName> method:

public Hand SecondHand { ... }
 
void ResetSecondHand() {
   SecondHand = new Hand(Color.Red, 1);
   }

Implementing ShouldSerialize lets the design-time environment know whether the property should be serialized, but you also need to write custom code to help assist in the generation of appropriate InitializeComponent code. Specifically, the Designer needs an instance descriptor, which provides the information needed to create an instance of a particular type. The code serializer gets an InstanceDescriptor object for a Hand by asking the Hand type converter:

public class HandConverter : ExpandableObjectConverter {
  public override bool
 
    CanConvertTo(
      ITypeDescriptorContext context, Type destinationType) {
 
     // We can be converted to an InstanceDescriptor
     if( destinationType == typeof(InstanceDescriptor) ) return true;
     return base.CanConvertTo(context, destinationType);
     }
   
   public override object
   ConvertTo(
     ITypeDescriptorContext context, CultureInfo culture,
     object value, Type destinationType) {
   
     if( value is Hand ) {
       // Convert to InstanceDescriptor
       if( destinationType == typeof(InstanceDescriptor) ) {
         Hand     hand = (Hand)value;
         object[] properties = new object[2];
         Type[]   types = new Type[2];
   
         // Color
         types[0] = typeof(Color);
         properties[0] = hand.Color;
   
         // Width
         types[1] = typeof(int);
         properties[1] = hand.Width;
   
         // Build constructor
         ConstructorInfo ci = typeof(Hand).GetConstructor(types);
         return new InstanceDescriptor(ci, properties);
         }
       ...
       }
     return base.ConvertTo(context, culture, value, destinationType);
   }
   ...
   }

To be useful, an instance descriptor requires two pieces of information. First, it needs to know what the constructor looks like. Second, it needs to know which property values should be used if the object is instantiated. The former is described by the ConstructorInfo type, and the latter is simply an array of values, which should be in constructor parameter order. After the control is rebuilt and assuming that ShouldSerialize<PropertyName> permits, all Hand type properties will be serialized using the information provided by the HandConverter-provided InstanceDescriptor:

public class ClockControlHostForm : Form {
  ...
  void InitializeComponent() {
    ...
    this.clockControl1.HourHand =
       new ClockControlLibrary.Hand(System.Drawing.Color.Black, 2);
     ...
     }
   }

Type converters provide all kinds of help for the Property Browser and the Designer to display, convert, and serialize properties of custom types for components that use such properties.


Previous_Page_.gif Next_Page_.gif

Today's Deals: Electronics

Personal tools