托管Windows Forms Designer-运行时序列化和DesignSurface [关闭]

问题描述 投票:0回答:1
我正在创建设计器图面并将控件加载到运行时。在反序列化/将控件加载到运行时时出现问题。

我尝试过的所有方法似乎都存在某种类型的问题。

例如,面临问题:

    控件仍受设计时限制
  • 并非所有属性都与所有属性(即嵌套属性)反序列化。
  • 似乎确实遵循了控件关联,即面板中的按钮不再存在于面板中,即使该属性在加载后仍是父级。
  • 我已经在git上创建了一个示例项目:Surface Designer Test

    有主要的代码片段:

    从设计开始的序列化

    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中更改它们的所有属性后,将它们的所有属性序列化,并在运行时将其加载回该程序。

    在设计时和运行时之间完成此序列化的正确方法是什么?

  • c# .net winforms windows-forms-designer codedom
    1个回答
    0
    投票
    这是我从设计图面生成代码的方式:

    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); }

    这是生成的代码:

    enter image description here

    然后运行它:

    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");

    © www.soinside.com 2019 - 2024. All rights reserved.