【问题标题】:Serializing Custom types that are set from UITypeEditor at design Time序列化在设计时从 UITypeEditor 设置的自定义类型
【发布时间】:2017-11-10 14:05:43
【问题描述】:

您好,我有一个自定义通用表单、自定义类型和一个 UITypeEditor,其中包含它的表单。

我可以在设计时设置和编辑我的自定义类型列表。我的问题是。设置后,不会序列化到designer.cs文件。

我在这里遗漏了什么吗?

我的自定义表单:

 public partial class MyBrowseForm<TParentEntity> : Form where TParentEntity:class
{


    private BindingList<MyBindingFields> _myBindingFieldsCollection = new BindingList<MyBindingFields>();

   [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    [Editor(typeof(BdFormTypeEditor), typeof(UITypeEditor))]
    [TypeConverter(typeof(ExpandableObjectConverter))]        
    public BindingList<MyBindingFields> MyBindingFieldsCollection
    {
        get => _myBindingFieldsCollection;
        set => _myBindingFieldsCollection = value;
    }
}

类型编辑器

class BdFormTypeEditor : UITypeEditor
{
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        return UITypeEditorEditStyle.Modal;
    }
    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {        
        var svc = provider.GetService(typeof(IWindowsFormsEditorService))
            as IWindowsFormsEditorService;

        BindingList<MyBindingFields> bindingFieldsList = context.Instance.GetPropValue("MyBindingFieldsCollection") as BindingList<MyBindingFields>;

        var myGenericTypeProperty = context?.Instance.GetType()
        .GetProperty("MyGenericType");                         
        var genericArgument = (Type)myGenericTypeProperty.GetValue(context.Instance);
        var editorFormType = typeof(MyEditorForm<>);
        var genericArguments = new[] { genericArgument };
        var editorFormInstance = editorFormType.MakeGenericType(genericType);
        if (svc != null)
        {
            using (var f = (Form) Activator.CreateInstance(editorFormInstance))
            {                    
                ((dynamic) f).MyBindingFieldsList = bindingFieldsList;

                f.ShowDialog();
                            context.Instance.GetType().GetProperty("MyBindingFieldsCollection")?.SetValue(context.Instance, ((dynamic)f).MyBindingFieldsList); 
            }

        }
        else
        {
            using (var f = (Form)Activator.CreateInstance(editorFormInstance))
            {                   
                ((dynamic)f).MyBindingFieldsList = bindingFieldsList;

                f.ShowDialog();
     context.Instance.GetType().GetProperty("MyBindingFieldsCollection")?.SetValue(context.Instance, ((dynamic)f).MyBindingFieldsList);  

            }
        }
        return value; 
    }
}

MyBindingFields 类:

public class MyBindingFields
{
    private ControlTypes _ControlType;
    public ControlTypes ControlType
    {
        get => _ControlType;
        set => _ControlType = value;
    }

    //public string MyParentEntity { get; set; }
    public string BindingField { get; set; }

    public string ChildEntity { get; set; }
    public string ValueMember { get; set; }
    public string DisplayMember { get; set; }
}

所以在我设置值并按保存之后会发生什么。 这些值存储在,当我单击以再次打开此窗口时。我有我以前的记录,如果我添加新记录也很好。这里的问题是由于这个原因数据没有序列化到designer.cs文件。当我运行程序或清理并重建解决方案时,我会丢失这些数据。 我在这里想念什么?我该怎么做才能在按下保存按钮时将数据序列化到designer.cs?

【问题讨论】:

  • 数据只有通过公共属性公开且类型具有 [Serializable] 属性时才能序列化为 InitializeComponent()。不要过度这样做,这是非常危险的。设计时的异常,比如你在改变类型时会得到的那种,会导致非常讨厌的问题。 InitializeComponent() 不是一个很好的数据库。
  • 我在这里只存储字符串值。即使我将可序列化属性放在 MyBindingFields 类的顶部,它仍然无法完成这项工作。那么有什么建议吗?
  • 这里,问题不是Serializable属性。事实上,您不需要将模型标记为可序列化。相反,您应该使用CollectionConverter 作为属性的类型转换器。目前在您的代码中,编辑器也不会返回编辑后的值。您应该在ShowDialog 之后返回从对话框中获得的值。您需要应用一些更改才能使代码正常工作。

标签: c# winforms generics windows-forms-designer uitypeeditor


【解决方案1】:

要使用自定义编辑器使 BindingList&lt;MySampleModel&gt; 可编辑,您需要应用以下更改:

1) 该属性应由CollectionConverter 装饰:

public partial class MyBaseForm<T> : Form
{
    public MyBaseForm()
    {
        InitializeComponent();
    }

    BindingList<MySampleModel> someProperty = new BindingList<MySampleModel>();
    [Editor(typeof(MyUITypeEditor), typeof(UITypeEditor))]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    [TypeConverter(typeof(CollectionConverter))]
    public BindingList<MySampleModel> SomeProperty
    {
        get { return someProperty; }
        set { someProperty = value; }
    }

    [Browsable(false)]
    public Type MyGenericType { get { return typeof(MySampleModel); } }
}

那么对于DerivedForm

public partial class MyDerivedForm : MyBaseForm<MySampleModel>
{
    public MyDerivedForm()
    {
        InitializeComponent();
    }
}

注意:不需要YourModel 标记为Serializer。您的模型将以这种方式序列化:

MCVE.MySampleModel mySampleModel1 = new MCVE.MySampleModel();
MCVE.MySampleModel mySampleModel2 = new MCVE.MySampleModel();
...
...
mySampleModel1.Id = 1;
mySampleModel1.Name = "X";
mySampleModel1.Price = 100;
mySampleModel2.Id = 2;
mySampleModel2.Name = "Y";
mySampleModel2.Price = 200;
this.SomeProperty.Add(mySampleModel1);
this.SomeProperty.Add(mySampleModel2);
...
...

2)MyEditorForm中,您应该在编辑后返回BindingList的新实例,以使设计器序列化列表:

public partial class MyEditorForm<T> : Form
{
    public MyEditorForm()
    {
        InitializeComponent();
        this.StartPosition = FormStartPosition.CenterScreen;
    }
    public BindingList<T> List
    {
        get
        {
            return (BindingList<T>)dataGridView1.DataSource;
        }
        set
        {
            if (value == null)
                value = new BindingList<T>();
            dataGridView1.DataSource = new BindingList<T>(value);
        }
    }
    private void button1_Click(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.OK;
    }
} 

3) 在您的UITypeEditor 中,您应该在对话框关闭后返回值:

public override object EditValue(ITypeDescriptorContext context,
    IServiceProvider provider, object value)
{
    var svc = provider.GetService(typeof(IWindowsFormsEditorService))
        as IWindowsFormsEditorService;
    var myGenericTypeProperty = context.Instance.GetType()
        .GetProperty("MyGenericType");
    var genericArgument = (Type)myGenericTypeProperty.GetValue(context.Instance);
    var editorFormType = typeof(MyEditorForm<>);
    var genericArguments = new[] { genericArgument };
    var editorFormInstance = editorFormType.MakeGenericType(genericArguments);
    if (svc != null) {
        using (var f = (Form)Activator.CreateInstance(editorFormInstance)) {
            f.GetType().GetProperty("List").SetValue(f, value);
            if (svc.ShowDialog(f) == DialogResult.OK)
                return ((dynamic)f).List;
        }
    }
    else {
        using (var f = (Form)Activator.CreateInstance(editorFormInstance)) {
            f.GetType().GetProperty("List").SetValue(f, value);
            if (f.ShowDialog() == DialogResult.OK)
                return ((dynamic)f).List;
        }
    }
    return base.EditValue(context, provider, value);
}

【讨论】:

  • 我已经用我的代码示例测试了该解决方案,它可以正常工作。我的代码示例和您的代码之间存在一些细微差别,这对答案的整体没有任何改变。如果您在应用该解决方案时遇到任何问题,请告诉我。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多