【发布时间】:2023-04-05 17:56:01
【问题描述】:
我正在创建一个设计器界面并将控件加载到运行时。 将控件反序列化/加载到运行时时遇到问题。
我尝试过的所有方法似乎都存在某种问题。
问题面临的例子:
- 控件仍受设计时约束
- 并非所有属性都使用所有属性(即嵌套属性)反序列化。
- 似乎确实遵循了控件关联,即面板中的按钮将不再出现在面板中,即使该属性在加载后仍然是父级。
我在 git 上创建了一个示例项目:Surface Designer Test
主要有sn-ps代码:
从设计时序列化
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;
}
运行时反序列化
这里是反射的尝试:
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);
}
}
这里是直接加载控件的尝试(仍然绑定到设计时):
MemoryStream ms = new MemoryStream(SaveData.Data);
Designer d = new Designer();
var controls = d._designerSerializationService.Deserialize(ms);
foreach (Control cont in controls)
Controls.Add(cont);
我觉得我错过了System.ComponentModel.Design 框架中的一个概念。
我也不认为有必要为每个控件编写一个自定义序列化程序,因为当然已经有了这个,Visual Studio 能够序列化它们的所有属性,因为它们在PropertyGrid 中更改并加载它们回来当你运行程序时。
我很想将设计器序列化成一个.cs 文件,但是怎么做?你如何序列化控件/表单并将属性更改为像 VS 设计器这样的文件,我尝试并只查找 xml 和二进制序列化程序。我理想的解决方案是使用CodeDom 构建designer.cs。
在设计时和运行时之间完成这种序列化的正确方法是什么?
【问题讨论】:
-
你应该序列化整个表单。然后加载表单,编译并运行它。
-
@RezaAghaei 它产生了确切的示例问题:(
-
通过序列化,我的意思是序列化到一个文本文件,就像 VS 为你做的那样,当你打开文件时,你应该看到类似
designer.cs文件的东西。然后就需要加载编译运行了。 -
@RezaAghaei 我很想这样做,但是怎么做呢?你如何序列化控件/表单并将属性更改为像设计器这样的文件,我尝试并只查找 xml 和二进制序列化程序。我理想的解决方案是按照您的建议使用 CodeDom 构建 Designer.cs。你能提供一个解决方案吗?
标签: c# .net winforms windows-forms-designer codedom