我尝试过的所有方法似乎都存在某种类型的问题。
例如,面临问题:
有主要的代码片段:
从设计开始的序列化
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能够在System.ComponentModel.Design
中更改它们的所有属性后,将它们的所有属性序列化,并在运行时将其加载回该程序。在设计时和运行时之间完成此序列化的正确方法是什么?
PropertyGrid
您可以像这样创建设计图面:
string GenerateCSFromDesigner(DesignSurface designSurface) { CodeTypeDeclaration type; var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost)); var root = host.RootComponent; var manager = new DesignerSerializationManager(host); using (manager.CreateSession()) { var serializer = (TypeCodeDomSerializer)manager.GetSerializer(root.GetType(), typeof(TypeCodeDomSerializer)); type = serializer.Serialize(manager, root, host.Container.Components); type.IsPartial = true; type.Members.OfType<CodeConstructor>() .FirstOrDefault().Attributes = MemberAttributes.Public; } var builder = new StringBuilder(); CodeGeneratorOptions option = new CodeGeneratorOptions(); option.BracingStyle = "C"; option.BlankLinesBetweenMembers = false; using (var writer = new StringWriter(builder, CultureInfo.InvariantCulture)) { using (var codeDomProvider = new CSharpCodeProvider()) { codeDomProvider.GenerateCodeFromType(type, writer, option); } return builder.ToString(); } }
因此,您将看到如下形式:
DesignSurface designSurface; private void Form1_Load(object sender, EventArgs e) { designSurface = new DesignSurface(typeof(Form)); var host = (IDesignerHost)designSurface.GetService(typeof(IDesignerHost)); var root = (Form)host.RootComponent; TypeDescriptor.GetProperties(root)["Name"].SetValue(root, "Form1"); root.Text = "Form1"; var button1 = (Button)host.CreateComponent(typeof(Button), "button1"); button1.Text = "button1"; button1.Location = new Point(8, 8); root.Controls.Add(button1); var timer1 = (Timer)host.CreateComponent(typeof(Timer), "timer1"); timer1.Interval = 2000; var view = (Control)designSurface.View; view.Dock = DockStyle.Fill; view.BackColor = Color.White; this.Controls.Add(view); }
这是生成的代码:
然后运行它:
public partial class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.Button button1; private System.Windows.Forms.Timer timer1; private System.ComponentModel.IContainer components; public Form1() { this.InitializeComponent(); } private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.button1 = new System.Windows.Forms.Button(); this.timer1 = new System.Windows.Forms.Timer(this.components); this.SuspendLayout(); // // button1 // this.button1.Location = new System.Drawing.Point(8, 8); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(75, 23); this.button1.TabIndex = 0; this.button1.Text = "button1"; // // timer1 // this.timer1.Interval = 2000; // // Form1 // this.ClientSize = new System.Drawing.Size(284, 261); this.Controls.Add(this.button1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); } }
例如:
void Run(string code, string formName) { var csc = new CSharpCodeProvider(); var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Windows.Forms.dll", "System.dll", "System.Drawing.dll", "System.Core.dll", "Microsoft.CSharp.dll"}); parameters.GenerateExecutable = true; code = $@" {code} public class Program {{ [System.STAThread] static void Main() {{ System.Windows.Forms.Application.EnableVisualStyles(); System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false); System.Windows.Forms.Application.Run(new {formName}()); }} }}"; var results = csc.CompileAssemblyFromSource(parameters, code); if (!results.Errors.HasErrors) { System.Diagnostics.Process.Start(results.CompiledAssembly.CodeBase); } else { var errors = string.Join(Environment.NewLine, results.Errors.Cast<CompilerError>().Select(x => x.ErrorText)); MessageBox.Show(errors); } }
哪个显示:
Run(GenerateCSFromDesigner(designSurface), "Form1");