Actually, the above example does nest InstanceDescriptors indirectly. There isn't any way I know of to nest InstanceDescriptors directly since each value of the argument array is intended to be a value to be serialized -- not a representation of that value.
For your second question (serializing the value as a property) -- this can be done in a similar way, but you still have to use a custom Type. You could change the serializer for string, but you'd probably would break other components in the designer if you did this.
You can change the serializer for the whole control if you want and then serialize the returned statements from the original serializer. I wouldn't recommend this since you are taking a dependency on implementation -- which is sure to break later.
I show this in the example below. Sorry I cannot provide more help as this is about as close I can get to your requests. About marking posts as answers -- it does not mean your post will not get further comments or posts if a post is marked as an answer. It just allows us to mark samples or snippets so they can be found by others.
Ideally, what you want is to be able to mark a single property with a specific DesignerSerializer. We will look at this in the future, but I cannot make any promises.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.Windows.Forms.Design;
using System.ComponentModel.Design.Serialization;
using System.Reflection;
using System.CodeDom;
namespace WindowsApplication122
{
[DesignerSerializer(typeof(MyControlSerializer), typeof(CodeDomSerializer))]
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
MyClass myProperty = new MyClass(typeof(MyOtherClass), MyOtherClass.FldMyField);
public MyClass MyProperty
{
get { return myProperty; }
set { myProperty = value; }
}
MyStringClass myProperty2 = MyOtherClass.FldMyField;
public MyStringClass MyProperty2 {
get { return myProperty2; }
set { myProperty2 = value; }
}
}
public class MyControlSerializer : CodeDomSerializer {
public override object Serialize(IDesignerSerializationManager manager, object value) {
CodeDomSerializer serializer = GetSerializer(manager, this.GetType().BaseType);
object result = serializer.Serialize(manager, value);
//result is a codestatementcollection.
//you could parse this and change it, but I wouldn't recommend it.
return result;
}
}
[TypeConverter(typeof(MyClassConverter))]
public class MyClass {
public MyClass(Type t, MyStringClass param2)
{
}
}
public class MyStringClassSerializer : CodeDomSerializer {
public override object Serialize(IDesignerSerializationManager manager, object value) {
if (value is MyStringClass && ((MyStringClass)value) == MyOtherClass.FldMyField) {
return new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(MyOtherClass)), "FldMyField");
}
return base.Serialize(manager, value);
}
}
public class MyClassConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(InstanceDescriptor))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType != typeof(InstanceDescriptor))
{
return base.ConvertTo(context, culture, value, destinationType);
}
//instancedescriptor...
ConstructorInfo c = typeof(MyClass).GetConstructor(new Type[] { typeof(Type), typeof(MyStringClass) });
if (null == c)
{
throw new ApplicationException("MyClass constructor not found");
}
InstanceDescriptor classInstance = new InstanceDescriptor(c,
new object[] { typeof(MyOtherClass), MyOtherClass.FldMyField });
return classInstance;
}
}
public class MyOtherClass
{
public static MyStringClass FldMyField = new MyStringClass("FldMyFieldVal");
public static MyStringClass Default = new MyStringClass("DefaultVal");
}
[TypeConverter(typeof(MyStringConverter))]
[DesignerSerializer(typeof(MyStringClassSerializer), typeof(CodeDomSerializer))]
public class MyStringClass
{
string _val;
public string Val
{
get { return _val; }
set { _val = value; }
}
public MyStringClass(string value)
{
_val = value;
}
}
class MyStringConverter : TypeConverter
{
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(InstanceDescriptor))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType != typeof(InstanceDescriptor))
{
return base.ConvertTo(context, culture, value, destinationType);
}
MyStringClass strVal = value as MyStringClass;
if (strVal == null) {
return null;
}
if (strVal.Val == "FldMyFieldVal")
{
return new InstanceDescriptor(typeof(MyOtherClass).GetField("FldMyField", BindingFlags.Static | BindingFlags.Public),
null);
}
else
{
return new InstanceDescriptor(typeof(MyOtherClass).GetField("Default", BindingFlags.Static | BindingFlags.Public),
null);
}
}
}
}