【问题标题】:C# Serialize WinFormC# 序列化 WinForm
【发布时间】:2016-04-30 04:36:36
【问题描述】:

我正在尝试序列化一个 winform,最终目标是能够在表单的各种控件中重新创建值。我的表单包含典型的控件,按钮/单选按钮/复选框/文本框/列表框/选项卡控件。

我收到此错误:

An exception of type 'System.InvalidOperationException' occurred 
in System.Xml.dll but was not handled in user code

Additional information: There was an error reflecting type 
'Receptionist_Program.Objects.Client.Client_NCQ'.

我为每个要保存的值设置属性:

    public bool CbMedTreat
    {
        get { return cbMedTreat.Checked; }
        set { cbMedTreat.Checked = value; }
    }

    public List<Client_AddDoctor> TxtDocExplain // Client_AddDoctor is another form
    {
        get { return listDoctors; }
        set { listDoctors = value; }
    }
    // etc, variety of string and bool properties

在班级的顶部我有装饰:

    [Serializable]
    public partial class Client_NCQ : Form

最后,这是我做序列化的代码:

            Client_NCQ badname = new Client_NCQ();
        badname.Initialize();
        badname.ShowDialog();

        string result = "";

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(Client_NCQ));
        // Error occurs here on above line: new XmlSerializer(typeof(Client_NCQ))
        using (StringWriter textWriter = new StringWriter())
        {
            xmlSerializer.Serialize(textWriter, badname);
            result = textWriter.ToString();
        }

到目前为止,我尝试了两种不同的方法,首先,我将装饰 [XmlIgnore] 添加到 List 属性中,这没有区别。其次,我尝试确保构造函数为空且没有参数。

【问题讨论】:

  • 你的InnerException 是什么?它应该为您提供有关其存在问题的属性的详细信息。如果表单上有非可视组件,我打赌Site
  • 第一级:{"Cannot serialize member 'System.ComponentModel.Component.Site' of type 'System.ComponentModel.ISite', see inner exception for more details."}。在该异常中,是最后一个内部异常:{"Cannot serialize member System.ComponentModel.Component.Site of type System.ComponentModel.ISite because it is an interface."}
  • 是的,我赢了! :-) 我认为您不能按原样序列化表单,因为它有一些不可序列化的组件。您需要将数据与表单分开,并仅序列化数据
  • 有道理,我将创建一个单独的对象并使用它来填充表单。非常感谢您的帮助!

标签: c# xml winforms serialization


【解决方案1】:

序列化整个Form 是个坏主意,因为它不应该被序列化:

  • 它有很多不应该序列化的属性(例如显示相关属性)
  • 即使它工作正常,您也会有大量与您的应用程序状态无关的数据

正确的解决方案是将所有状态信息保留在您的自定义对象中,并使用 WinForm 的databinding 功能绑定到这些对象。如果这意味着对您的应用程序进行重大更改,请尝试仅序列化与构造状态相关的数据。

您如何知道哪些数据与应用程序状态相关?

在构造和显示表单之前,我希望您从数据库、文件等加载数据。所有这些信息都应该包含在明确定义的类型对象中,这些对象类型标记为[Serializable] 属性。这样就很容易随意序列化和反序列化了。

此外,重要的是要考虑version tolerant serialization 或当表单/状态信息发生更改(例如添加一个字段)并且使用旧的 XML 来恢复状态时会发生什么。

【讨论】:

  • 谢谢阿列克谢。我将开始研究数据绑定功能
  • 即使没有数据绑定(需要一些时间来适应使用它,当然,还要在很多地方更改代码),您必须在应用程序数据(模型)和视图(用户界面)。这也允许在一层中更轻松地更改对另一层的影响最小(例如,使用自定义数据选择器而不是标准选择器)
  • @Alexei - 好答案。
  • @BrianCombs - 您可以忽略数据绑定,只需对数据对象进行简单的分配,如果这样更容易的话。数据绑定将是可行的方法,但它可能会带来其他复杂性。
  • @Enigmativity 这就是我最终所做的。用于存储我的数据的自定义类,在构造函数中填充并在 FormClosing 事件中分配。所以我对类进行序列化和反序列化,然后将其传递给表单的新实例,并在用户关闭表单时从表单中检索更新的版本。
【解决方案2】:

每个表单都有自己的机制来存储和检索(序列化和反序列化)数据,并且它会自动执行此操作。但是,要自动使用此功能,必须满足以下条件。

-  All properties which are desired to be serialized must have public get and set accesor.
 - If a certain property represents custom object such as user defined class or struct, the object must be adorned with [Serializable] attribute.
 - Property which is desired to be serialized must not have [DesignerSerializationVisibility] attribute set to Hidden. By default it is Visible so not specifying this attribute at all is sufficiently serves the purpose.

考虑这个例子:

namespace MnM.Drawing
{
    [Serializable, TypeConverter(typeof(ExpandableObjectConverter))]
    public class Coordinates
    {
        public int X { get; set; }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public int Y { get; set; }

        public int Z { get; protected set; }
    }

    public class MyForm : Form
    {

        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public Coordinates MyCoordinates { get; set; }
    }
}

现在,MyForm 会自动序列化 MyCoordinates 对象,但是...

  • 只有属性 X 会被序列化,因为它符合要求 状态以符合自动序列化的条件。
  • 属性 Y 无法序列化,因为 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
  • 属性 Z 无法自动序列化,因为它可以 没有公共集访问器。

为了序列化 Y 和 Z,需要自定义序列化代码。在大多数情况下,不会出现自定义序列化的需求,并且可以通过多种方式完成自定义序列化,但这是一个庞大的主题。

【讨论】:

  • 并不是我在抱怨,但知道我的错误导致投票否决会有所帮助,以便我可以纠正它。一个人无法在自己的逻辑和理解上找错。我要求对我的答案投反对票的人至少对答案有什么问题发表简短评论。
  • 问题是您在谈论“代码序列化”(设计师如何将属性序列化为代码),而问题完全不同,它是在询问表单生成类的 Xml 序列化(其中作为公认的答案和我最初的 cmets 提示,在大多数情况下是不可行的)。
  • 感谢您花时间解释。我的意图是在更广泛的点上发光。那一点就是需要自定义序列化。为什么我们首先需要它?当框架已经能够完成你想要的事情时,为什么要把事情复杂化。无论如何,我倾向于同意也许我的方法可能会有所不同。我希望能学到更多。非常感谢您的回复。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-19
  • 2021-11-18
  • 2013-10-12
  • 2011-05-12
相关资源
最近更新 更多