shingo
shingo

Reputation: 27076

How to save a struct property of a user control in Windows Forms Designer?

I've checked the answers of this question: Modifying structure property in a PropertyGrid

And also SizeConverter from .net.

But not helpful, my property is still not saved.


I have a struct, a user control, and a custom type converter.

public partial class UserControl1 : UserControl
{
    public Bar bar { get; set; } = new Bar();
}

[TypeConverter(typeof(BarConverter))]
public struct Bar
{
    public string Text { get; set; }
}

public class BarConverter : ExpandableObjectConverter
{
    public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
    {
        return true;
    }

    public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
    {
        if (propertyValues != null && propertyValues.Contains("Text"))
            return new Bar { Text = (string)propertyValues["Text"] };
        return new Bar();
    }
}

After compile, I drag the control in a form then I can see the property Bar.Text showed in the properties window, I also can edit the value and it seems be saved.


But nothing is generated in the InitializeComponent method

nothing generated

So if I reopen the designer, the Text field in the properties window become empty.

Please notice the struct hasn't a custom constructor, so I cannot use InstanceDescriptor.

Do I miss any important steps?

Upvotes: 2

Views: 926

Answers (1)

Reza Aghaei
Reza Aghaei

Reputation: 125217

You are missing a few method overrides in the type descriptor:

public class BarConverter : ExpandableObjectConverter
{
    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, 
        CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(InstanceDescriptor))
        {
            ConstructorInfo ci = typeof(Bar).GetConstructor(new Type[] { typeof(string) });
            Bar t = (Bar)value;
            return new InstanceDescriptor(ci, new object[] { t.Text });
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
    public override object CreateInstance(ITypeDescriptorContext context, 
        IDictionary propertyValues)
    {
        if (propertyValues == null)
            throw new ArgumentNullException("propertyValues");
        object text = propertyValues["Text"];
        return new Bar((string)text);
    }
    public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
    {
        return true;
    }
}

And add constructor to the struct:

[TypeConverter(typeof(BarConverter))]
public struct Bar
{
    public Bar(string text)
    {
        Text = text;
    }
    public string Text { get; set; }
}

And this is how the Bar property serializes:

// 
// userControl11
// 
this.userControl11.Bar = new SampleWinApp.Bar("Something");

And the bar property will be shown like following image in property grid, having Text property editable:

enter image description here

You may also want to provide a better string representation for the struct by overriding its ToString() method of the struct, and also make the property convertible from string in property grid, by overriding CanConvertFrom and ConvertFrom like PointConverter or SizeConverter.

Upvotes: 1

Related Questions