I am creating a designer surface and loading the controls to a runtime. I am having issues when deserializing/loading the controls to the runtime.
All methods I have tried seem to have some type of issue.
Issued faced for example:
- Controls are still bound of the design-time
- Not all properties deserialize with all the properties, namely nested properties.
- Control associations does seem to be followed, i.e. Button in a Panel, will not be in the panel anymore, even though the property is still the parent after loading.
I have created a sample Project on git here: Surface Designer Test
There are the main code snippets:
Serialization from the design-time
private void LoadRuntime(int type)
{
var controls = surface.ComponentContainer.Components;
SerializationStore data = (SerializationStore)surface.
_designerSerializationService.Serialize(controls);
MemoryStream ms = new MemoryStream();
data.Save(ms);
SaveData.Data = ms.ToArray();
SaveData.LoadType = type;
new RuntimeForm().Show();
}
public object Serialize(System.Collections.ICollection objects)
{
ComponentSerializationService componentSerializationService =
_serviceProvider.GetService(typeof(ComponentSerializationService)) as
ComponentSerializationService;
SerializationStore returnObject = null;
using (SerializationStore serializationStore =
componentSerializationService.CreateStore())
{
foreach (object obj in objects)
{
if (obj is Control control)
{
componentSerializationService.SerializeAbsolute(serializationStore, obj);
}
returnObject = serializationStore;
}
}
return returnObject;
}
Deserialization in runtime
Here is attempt with reflection:
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
ms.Close();
if (SaveData.LoadType == 1)
{
foreach (Control cont in controls)
{
var ts = Assembly.Load(cont.GetType().Assembly.FullName);
var o = ts.GetType(cont.GetType().FullName);
Control controlform = (Control)Activator.CreateInstance(o);
PropertyInfo[] controlProperties = cont.GetType().GetProperties();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite)
{
if (propInfo.Name != "Site" && propInfo.Name != WindowTarget")
{
try
{
var obj = propInfo.GetValue(cont, null);
propInfo.SetValue(controlform, obj, null);
}
catch { }
}
else { }
}
}
Controls.Add(controlform);
}
}
Here is attempt with loading controls directly (still bound to the design-time):
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
foreach (Control cont in controls)
Controls.Add(cont);
I feel like I am missing a concept from the System.ComponentModel.Design
framework.
I also do not believe there is a need to write a custom serializer for each control, as surely the already have this has Visual Studio is able to serialize all their properties as they are changed in the PropertyGrid
and load them back when you run the program.
I'd love to serialize the designer into a .cs
file, but how? How do you serialize controls/form and changed properties to a file like the VS designer, I tried and looked only to find xml and binary serializer. My ideal solution would be build a designer.cs
with the CodeDom
.
What is the correct way do accomplish this serialization between design-time and run-time?
Assuming you have a
DesignSurface
to show aForm
as root component of the designer and having some components created at run-time by usingCreateComponent
method ofIDesignerHost
, here is how I approach the problem:IDesignerHost
fromDesignSurface
DesignerSerializationManager
TypeCodeDomSerializer
from serialization managerRootComponent
of theIDesignerHost
CSharpCodeProvider
GenerateCodeFromType
and passing the serialized root component.You can also extend the example a bit and use
ISelectionService
to get notified about selected components and change properties at run-time using aPropertyGrid
:Example - Generate C# code from DesignSurface at runtime
Here in this example, I'll show how you can host a windows forms designer at run-time and design a form containing some controls and components and generate C# code at run-time and run the generated code.
Create the DesignSurface and host the designer
You can create the design surface like this:
Generate C# code using TypeCodeDomSerializer and CSharpCodeProvider
This is how I generate code from design surface:
For example:
Run the code sing CSharpCodeProvider
Then to run it:
For example: