I have an assembly which contains several UserControl objects that I want to be able to save/load via the application UI. To do this, each control implements the ISerializable interface to customize the fields they need to save.
Here’s a simplified version of that library:
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);
}
}
}
The client application instantiates several of this controls, and allows the user saving/loading the various UserControl configurations. Here’s a simplified version of the application:
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();
}
}
}
On SaveClick, the values are properly saved to file.
On LoadClick, the CheckBox.Checked is properly updated in the Debugger Watch list, but the UI doesn’t reflect the new value.
I have tried adding calls to Refresh(), Invalidate(), Update(), but nothing seems to work.
As expected, hash1 and hash2 are different, but Form1 uses the correct instance.
What am I doing wrong, and how can I fix the UI to display the correct (updated) value?
EDIT: Also, notice that I need to handle multiple config files, that the user must have the ability to save/load to/from a path of her choice
I’m not sure but I’m going to guess it’s because
InitializeComponentdoesn’t get called.But to solve your problem, it is better to serialize a surrogate. Just make little surrogate classes marked [Serializable] and copy properties from the UserControl to the surrogate before serialization. Then you don’t have to mess around with
GetObjectData– the serialization process just assumes every property of the surrogate should be serialized.The deserialization process will give you a surrogate back. The surrogate just has to know how to instantiate a UserControl and map the properties back to it.
And if you define a common interface, you don’t have to know which specific type of UserControl you are deserializing:
Here’s an example of how a surrogate might look:
Update
Actually, I bet the problem is that you’re simply reassigning
this.ctrl, which doesn’t change which controls are on the form. What you actually need to do is something like this:But you should still use serialization surrogates. They make this kind of stuff much easier.