反序列化为UI

Gus*_*ori 6 c# user-interface deserialization

我有一个程序集,其中包含几个UserControl我希望能够通过应用程序UI保存/加载的对象.为此,每个控件都实现ISerializable接口以自定义需要保存的字段.

这是该库的简化版本:

namespace LibraryProject
{
    using System;
    using System.Runtime.Serialization;
    using System.Windows.Forms;

    [Serializable]
    public partial class UserControl1 : UserControl, ISerializable
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public UserControl1(SerializationInfo info, StreamingContext ctxt)
            : this()
        {
            this.checkBox1.Checked = info.GetBoolean("Checked");
        }

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("Checked", this.checkBox1.Checked);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

客户端应用程序实例化其中的几个控件,并允许用户保存/加载各种UserControl配置.这是应用程序的简化版本:

namespace ApplicationProject
{
    using System;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Soap;
    using System.Windows.Forms;
    using LibraryProject;

    public partial class Form1 : Form
    {
        private const string filename = @"test.xml";

        //int hash1;
        //int hash2;

        public Form1()
        {
            InitializeComponent();

            //hash1 = this.ctrl1.GetHashCode();
        }

        private void SaveClick(object sender, EventArgs e)
        {
            using (var stream = File.Open(filename, FileMode.Create))
            {
                var formatter = new SoapFormatter();

                formatter.Serialize(stream, this.ctrl1);
            }
        }

        private void LoadClick(object sender, EventArgs e)
        {
            using (var stream = File.Open(filename, FileMode.Open))
            {
                var formatter = new SoapFormatter();

                this.ctrl1= (UserControl1)formatter.Deserialize(stream);
            }

            //hash2 = this.ctrl1.GetHashCode();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

SaveClick,值正确保存到文件.On LoadClick,CheckBox.Checked在Debugger Watch列表中正确更新,但UI不反映新值.

我曾尝试加入通话Refresh(),Invalidate(),Update(),但似乎没有任何工作.

正如所料,hash1并且hash2是不同的,但Form1使用正确的实例.

我做错了什么,如何修复UI以显示正确(更新)的值?

编辑:另外,请注意我需要处理多个配置文件,用户必须能够保存/加载到她选择的路径

def*_*mer 1

我不确定,但我猜这是因为InitializeComponent没有被调用。

但要解决您的问题,最好序列化代理。只需将小代理类标记为 [Serialized] 并在序列化之前将属性从 UserControl 复制到代理类即可。然后您不必乱搞GetObjectData- 序列化过程只是假设代理的每个属性都应该被序列化。

反序列化过程会给你一个代理返回。代理只需要知道如何实例化 UserControl 并将属性映射回它。

如果您定义了一个通用接口,则不必知道要反序列化的是哪种特定类型的 UserControl:

var surrogate = formatter.Deserialize(stream) as ISerializationSurrogate;
UserControl uc = surrogate.Create();
this.Controls.Add(uc);
Run Code Online (Sandbox Code Playgroud)

以下是代理人的外观示例:

[Serializable]
public class MySurrogate: ISerializationSurrogate
{
    public MySurrogate() {}

    public MySurrogate(MyControl control)
    {
        CB1Checked = control.checkBox1.Checked;
    }

    public bool CB1Checked { get; set; }

    public Control Create()
    {
        var control = new MyControl();
        control.checkBox1.Checked = CB1Checked;
        return control;
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

实际上,我敢打赌问题在于您只是重新分配this.ctrl,这不会改变表单上的控件。你实际上需要做的是这样的:

this.Controls.Remove(existingControl); // if it exists
this.Controls.Add(newControl);
Run Code Online (Sandbox Code Playgroud)

但您仍然应该使用序列化代理。他们使这类事情变得更加容易。