【问题标题】:How to save a struct property of a user control in Windows Forms Designer?如何在 Windows 窗体设计器中保存用户控件的结构属性?
【发布时间】:2019-03-08 09:01:04
【问题描述】:

我已经检查了这个问题的答案: Modifying structure property in a PropertyGrid

还有来自 .net 的 SizeConverter

但没有帮助,我的财产仍未保存。


我有一个结构、一个用户控件和一个自定义类型转换器。

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();
    }
}

编译完成后,将控件拖到窗体中,可以看到属性窗口显示Bar.Text属性,我也可以编辑值,好像保存了。


但是InitializeComponent 方法中没有生成任何内容

因此,如果我重新打开设计器,属性窗口中的文本字段将变为空。

请注意该结构没有自定义构造函数,所以我不能使用InstanceDescriptor

我是否遗漏了任何重要步骤?

【问题讨论】:

  • @MindSwipe 你能在投票前阅读这个问题吗?
  • 我做到了,>“但是 InitializeComponent 方法中没有生成任何内容”然后出现图像,为什么不直接发布代码?如果你经历了截图和上传图像的努力,为什么不只是 Ctrl + C、Ctrl + V?我看到了您发布代码的第一部分,但为什么要半途而废呢?
  • @MindSwipe 我只是想清楚地表明没有生成任何东西。如果我复制代码,有人可能会认为您可能会错误地丢失一些行。
  • 真正的代码被混淆到什么程度还不是很清楚。如果构造函数只需要一个字符串,那么您不应该使用结构而只需要一个普通字符串。否则,自定义类型需要 [Serializable] 属性,以便设计人员可以将值保留在表单的 .resx 文件中。
  • @MindSwipe IMO 图像在这种情况下是可以接受的,因为它显示了生成的代码,我们不会使用它来重现问题,我们只是尝试在视觉上验证它。

标签: c# .net winforms struct windows-forms-designer


【解决方案1】:

您在类型描述符中缺少一些方法覆盖:

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;
    }
}

并将构造函数添加到结构中:

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

这就是Bar 属性序列化的方式:

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

并且 bar 属性将在属性网格中显示如下图,Text 属性可编辑:

您可能还希望通过覆盖结构的ToString() 方法来为结构提供更好的字符串表示,并通过覆盖CanConvertFromConvertFrom 等@ 使属性可从属性网格中的字符串转换987654322@或SizeConverter

【讨论】:

  • 该结构没有构造函数,我应该添加一个吗?
  • 是的,应该有。
  • 是不是少了ConvertFrom这个部分?
  • @Jimi 对于ExpandableConverter,您可以忽略它,但是如果 OP 想要使属性可从属性网格中的字符串转换,他可以覆盖 CanConvertFromConvertFrom,如 @987654324 @ 或 SizeConverter.
  • 更多类似的:IconConverter : ExpandableObjectConverter。需要注意的是,我认为我实际上从未使用过ExpandableObjectConverter 类,只是通常 TypeConverter。但是我已经测试了代码,但没有得到预期的结果。也许是因为我期待 usual 结果。按原样阅读,我不能说 OP 想用它做什么。
猜你喜欢
  • 2016-10-18
  • 2013-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-05
  • 1970-01-01
  • 2011-05-28
  • 1970-01-01
相关资源
最近更新 更多