Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Serialization of custom colors (and other types)
 

Serialization of custom colors (and other types)

I have defined some custom colors (and fonts, etc.), and would like to be able to have designer serialize these as the custom types rather than numeric values. Here is a psuedo snippet:

// Implemented as a singleton... details are excluded
public class MyColors
{
  Color _myGray = new Color.FromArgb( 42, 42, 42 );

  public Color MyGray
  {
    get { return _myGray; }
  }
  // ... exclude other details ...
}

I apply MyColors.MyGray to the BackColor property of my custom control. Designer serializes the value as...

BackColor = Color.FromArgb( 42, 42, 42 );

Instead of...

BackColor = MyColors.Instance.MyGray;

How do I correct this? What do I need to implement? I know I need to create a custom UITypeEditor and TypeConverter but am not sure where to go from there. Thanks! 

Brent Yokota  Wednesday, January 04, 2006 6:31 PM

This is what I did to solve the problem and get the basic functionality I needed...

  • Create a property on MyControl like BackColorStyle that is a string type.
  • Create a UITypeEditor and apply it to the BackColorStyle property.
  • Create a VisualDesignSerializer which does special serialization for MyControl
    • If BackColorStyleequals "None" or null then do nothing extra.
    • Else remove the assignment statement for the BackColor property
    • Then add an new assignment statement for the BackColor property using a PropertyInfo from MyStaticColors which is found in a lookup table using the string value of BackColorStyle.

This works exactly how I wanted it to. It isa bit of a work around (without turning into an ugly hack)...the only option I see. Other types like Font could also be done this way.

Brent Yokota  Wednesday, January 18, 2006 6:29 PM

You dont need a UITypeEditor, you need a TypeConverter that can convert your custom class to an InstanceDescriptor object. Check out http://msdn.microsoft.com/msdnmag/issues/03/05/Design-TimeControls/ for an example. Basically you will need to use reflection to get a PropertyInfo object that represents your defined constant, and then pass that to the InstanceDescriptor constructor.

For anyone else who reads this, I am having an issue with my custom TypeConverter that is attempting to create a more complex nested InstanceDescriptor, and could really use the help of a designer guru. Read about my problem in this thread: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=187537&SiteID=1

CommonGenius.com  Wednesday, January 04, 2006 7:39 PM

I refactored code and now I have some static Color properties on some class instead of instance properties on a singleton. I went through http://msdn.microsoft.com/msdnmag/issues/03/05/Design-TimeControls/ and it helped me make progress (Thanks David). However, I still face a problem...

The designer property grid still complains, "Object of type 'System.String' cannot be converted to type 'System.Drawing.Color'." even though I placed a TypeConverter attribute on the color property.

Maybe the reason this is not working is that AttributeUsageAttribute.Inherited = true is default and the overriding of this method does not actually change the TypeConverter, but I doubt this. Here is the snippet...

[TypeConverter( typeof( MyColorConverter ) )]
[Editor( typeof( MyColorEditor ), typeof( UITypeEditor ) )]
public override Color BackColor
{
  get { ... }
  set { ... }
}

My converter returns true for CanConvertTo Color, and it returns a Color when ConvertTo is passed a String as the value object. It also returns a PropertyInfo whe nthe value object is an InstanceDescriptor. Has anyone had luck with overriding the default ColorEditor and FontEditor to provide serialization of your own static properties on a custom color definition class?

Brent Yokota  Tuesday, January 10, 2006 7:09 PM

You have it backwards. ConvertTo is used to convert your object (which in your case is a Color) to another type (usually a string, for the property browser). ConvertFrom is used to convert some other object (again, usually a string) into your object type (again, a Color in your case). So ConvertTo should return true for string (which it does by default, so you dont have to override CanConvertTo), and ConvertTo should be able to convert a Color object to a string. CanConvertFrom should return true for string, and ConvertFrom should be able to convert a string into a Color. What you probably want to do is maintain a static hashtable of your colors with their names (with the color value as the key). In ConvertTo, when it passes you a color object, you look up that color value in your hashtable and return it the property name for that color. In ConvertFrom, use reflection to get a PropertyInfo object for the property name it gives you, then call Invoke on that PropertyInfo to get the actual color value.

Getting the property to serialize correctly is another story; in serialization, the designer (apparently) always uses the TypeConverter for the type of the property, even if you have specified a different TypeConverter on the property itself. So in your InitializeComponent you would end up with "MyProperty = Color.FromArgb(r, g, b)", or Color.FromName('name')" if you were using a standard named color. I am still trying to find a solution to this, where it references your static property ("MyProperty = MyClass.MyColor").

CommonGenius.com  Tuesday, January 10, 2006 11:29 PM

I believe the answer may be to implement a custom CodeDomSerializer and apply it to the class with the Color property using the DesignerSerializer attribute. This may solve the serialization part of the issue at hand. I have yet to implement this, but here are a couple references:

Brent Yokota  Wednesday, January 11, 2006 11:03 PM

I tried creating a custom CodeDomSerializer and applying this to a control whose properties were set in designer. It did not seem to work. Perhaps, I am at error on how I constructed the statements, but I think I have come to the conclusion that "overriding" how custom static colors are set to Color properties is not straight forward, without major hacking.

Basically the built in serializer must look for the Color.Name property and serialize a KnownColor if this isn't null, if not then it serializes the ARGB values. There is no set on the Name property, so you would not be able to set the name of the Color to "MyColor"...obviously. So, then you are left with an ARGB value, which you could hash and lookup in a table, but then what if MyColor and MyOtherColor have the same ARGB values. At this point this is getting a little ugly.

Then, consider that you would likely have to place an Attribute or something on the controls or their properties that you would like this special serialization to take place. You would also need to mark each of these properties with a DesignerSerializationVisibility as Hidden. Then the CodeDomSerializer could go through each object and property to see if it found these properties, do a lookup in the table and execute a statement using the appropriate properties.

I think there may be simpler and more productive alternatives to this problem... by reapproaching how to set custom colors through indirect paths.

Brent Yokota  Thursday, January 12, 2006 8:20 PM

I got the serializer working and generating calls to my static Color properties. Now, I just need to create either a design-time only property or some other property which is basically a string so I can use it to set the BackColor in the serializer. I think this will work... indirectly.

Brent Yokota  Friday, January 13, 2006 10:12 PM

This is what I did to solve the problem and get the basic functionality I needed...

  • Create a property on MyControl like BackColorStyle that is a string type.
  • Create a UITypeEditor and apply it to the BackColorStyle property.
  • Create a VisualDesignSerializer which does special serialization for MyControl
    • If BackColorStyleequals "None" or null then do nothing extra.
    • Else remove the assignment statement for the BackColor property
    • Then add an new assignment statement for the BackColor property using a PropertyInfo from MyStaticColors which is found in a lookup table using the string value of BackColorStyle.

This works exactly how I wanted it to. It isa bit of a work around (without turning into an ugly hack)...the only option I see. Other types like Font could also be done this way.

Brent Yokota  Wednesday, January 18, 2006 6:29 PM
This sounds exactly like what I am trying to do. Could you post your code or a similar example of what you did in your VisualDesignSerializer? I tried a similar approach a while back but couldnt get it to work.
CommonGenius.com  Wednesday, January 18, 2006 11:19 PM

Follow the bulleted steps in the previous post, then in your serializer, override Serialize(...). In the Serialize method get the CodeStatementCollection and use something similar to following code:

System.CodeDom.CodeAssignStatement assign = new
  System.CodeDom.CodeAssignStatement();

System.CodeDom.CodePropertyReferenceExpression prop = new
  System.CodeDom.CodePropertyReferenceExpression(
    new System.CodeDom.CodeThisReferenceExpression(), "BackColor" );

System.CodeDom.CodeTypeReferenceExpression type = new
  System.CodeDom.CodeTypeReferenceExpression( typeof( MyCustomColors ) );

System.CodeDom.CodePropertyReferenceExpression color = new
  System.CodeDom.CodePropertyReferenceExpression(
    type, "MyColor" );

assign.Left = prop;
assign.Right = color;
statements.Add( assign );

See reference http://msdn.microsoft.com/netframework/programming/components/default.aspx?pull=/library/en-us/dndotnet/html/custcodegen.asp#custcodegen_topic8 

Brent Yokota  Thursday, January 19, 2006 2:06 AM

You can use google to search for other answers

Custom Search

More Threads

• Panels In Panels
• DLU vs Pixels
• Help persisting control collection
• UserControl, child control, and scrolling
• DesignSurface with Tabbed format
• Strange error after each time I change anything on the design
• Borders around ScrollableControl
• can web user control be placed any where on a webform
• Code generation with CodeDom
• How to use OLE in Vb.Net to edit Image?