2

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?

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
shingo
  • 18,436
  • 5
  • 23
  • 42
  • 2
    @MindSwipe could you read the question before vote? – shingo Mar 08 '19 at 09:06
  • I did, >"But nothing is generated in the InitializeComponent method" then comes an image, why not just post the code? If you went through the effort of screenshoting and uploading the image why not just Ctrl + C, Ctrl + V? I see the first part where you posted code, but why give up halfway trough? – MindSwipe Mar 08 '19 at 09:07
  • @MindSwipe I just want to clearly show **nothing is generated**. If I copy the code someone can think that you may lost some lines by mistake. – shingo Mar 08 '19 at 09:12
  • 2
    It is not so clear to what degree the real code is obfuscated. If the constructor only needs a string then you shouldn't use a struct but just a plain string. Otherwise a custom type needs the [Serializable] attribute so the designer can preserve the value in the form's .resx file. – Hans Passant Mar 08 '19 at 10:06
  • @MindSwipe IMO the image is acceptable in this case, because it's showing the generated code which we will not use for reproducing the problem and we just try to visually validate it. – Reza Aghaei Mar 08 '19 at 10:43
  • Thanks @HansPassant , this can be another choice. – shingo Mar 08 '19 at 10:51

1 Answers1

1

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.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • The struct doesn't has a constructor, so should I add one? – shingo Mar 08 '19 at 10:44
  • Yes, it should have. – Reza Aghaei Mar 08 '19 at 10:45
  • Isn't it missing the `ConvertFrom` part? – Jimi Mar 08 '19 at 11:33
  • @Jimi For an `ExpandableConverter` you can ignore it, however in case the OP wants to make the property convertible from string in property grid, he can override `CanConvertFrom` and `ConvertFrom` like [`PointConverter`](https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/PointConverter.cs,0e3a4309646c3111) or [`SizeConverter`](https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/SizeConverter.cs,86ceb450bb606020). – Reza Aghaei Mar 08 '19 at 15:07
  • More like this one: [IconConverter : ExpandableObjectConverter](https://referencesource.microsoft.com/#System.Drawing/commonui/System/Drawing/IconConverter.cs,29). To note, I don't think I've ever actually used an `ExpandableObjectConverter` class, just the *usual* `TypeConverter`. But I've tested the code and I don't have the results I'ld have expected. Maybe because I was expecting the *usual* result. Reading it as it is, I can't say what the OP wants to do with it. – Jimi Mar 09 '19 at 00:19
  • I have tried this converter, but I cannot achieve the serializable property in Designer.cs file. My struct has 5 properties, I modified converter to have all struct properties. After I change property value in design, if I check Designer.cs file, the property is not written in that file. What should I do? – Vali Maties Oct 21 '21 at 07:15
  • Worked, finally.... – Vali Maties Oct 21 '21 at 10:33
  • @ValiMaties Cool! Was there any missing piece in the answer? or was it just a mistake in your code? – Reza Aghaei Oct 21 '21 at 10:45
  • Converting your code to multiple properties in struct, I forgot to change some of the code... That's why my code had bug and it didn't save the property value. But I correct it and now it is working. Thanks @Reza – Vali Maties Oct 22 '21 at 06:35
  • @ValiMaties Awesome! No problem. – Reza Aghaei Oct 22 '21 at 08:10