3

我有大约 500 个由旧应用程序从 XML 文件动态生成的 WinForms。我想自动将这些转换为可以在设计器中编辑的 VB 或 C# 代码。

我可以手动完成,这将需要永远......

或者编写一个加载每个 XML 的应用程序,调用旧应用程序的 xml-to-winform-b​​uilder 以将其转换为完整的 WinForm,并检查每个控件的属性并使用 StringBuilder 生成设计人员可以接受的代码。这充其量是艰巨的。

但是:我想使用设计师使用的相同代码。我认为这将节省我处理极端情况的时间。

我想做的是,获取一个已经构建的 WinForm 对象,其中包含充满子控件的控件数组(由旧应用程序 xml-to-winform 代码创建),将其扔到 IDE 用于序列化设计表单的相同代码中到 CodeDom,并取回我可以用真实语言保存的 CodeDom 语句列表。一旦我得到 CodeDOM,我会很高兴的!

编辑

这篇 Codeproject文章体现了我想要做的“概念”:从完成的表单开始,将其转换(“序列化”)为代码。但是,它有两个不足:(1)它使用模板/字符串生成器生成 .aspx 页面,这就是属性所在(对于 webforms 很好,但 winforms 将属性序列化到实际的 .Designer.vb 文件中);(2) 这一切都是从头开始的。我想重用视觉工作室的例程。它们允许您使用许多东西来执行此操作,例如属性网格。我只是在寻找一篇文章的链接(也许我的 google-fu 太弱了),或者是某人已经做过的简短代码示例。

4

1 回答 1

5

因此,这可能符合您的需求,也可能不符合您的需求。我有一个解决方案,但它需要您调整 XML -> WinForms 渲染。

这在很大程度上依赖于这个项目的使用:http: //ivanz.com/files/docs/designerhosting/create-and-host-custom-designers-dot-net.html

下载 EXE(它只是带有 EULA 的源代码的压缩版本)并构建解决方案,我在构建时遇到了一些问题,直到我删除了对图形库的引用(以及从主机库中对它的相关调用)。为什么主机库需要绘制图表我不太确定......

然后我建立了一个新的 WinForms 项目(不能是控制台,因为 DesignSurface 无法挂钩拖放事件)。在新的 winforms 项目中引用上述项目中的 Host 和 Loader 项目。

毫无疑问,您需要在此处调整现有流程。合并您现有的流程,使其适合下面我的标签所示的这种类型的表单构建:

        HostSurfaceManager hsm = new HostSurfaceManager();
        HostControl hc = hsm.GetNewHost(typeof(Form), LoaderType.CodeDomDesignerLoader);

        var l = new Label() { Text = "TEST!!!!" };

        hc.DesignerHost.Container.Add(l);

        richTextBox1.Text = ((CodeDomHostLoader)hc.HostSurface.Loader).GetCode("C#");

这会生成您的 form.cs 文件内容(请参阅下面的生成代码)。这是一个多合一文件,您无需创建单独的 form.cs.designer 文件即可获得设计器支持。我复制了上面生成的代码,将其保存到 .cs 文件中,Visual Studio 将其识别为 winform 并为我提供了设计支持。

您的副本可能会包含一个子 Main。我进入 Loader -> CodeGen.cs 文件并注释掉与 Main 相关的部分,我建议你也这样做。

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:2.0.50727.5448
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

namespace DesignerHostSample
{
    using System;
    using System.ComponentModel;
    using System.Windows.Forms;


    public class Form1 : System.Windows.Forms.Form
    {

        private System.Windows.Forms.Label label1;

        public Form1()
        {
            this.InitializeComponent();
        }

        private void InitializeComponent()
        {
            this.label1 = new System.Windows.Forms.Label();
            this.SuspendLayout();
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(0, 0);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(100, 23);
            this.label1.TabIndex = 0;
            this.label1.Text = "TEST!!!!";
            // 
            // Form1
            // 
            this.ClientSize = new System.Drawing.Size(284, 262);
            this.Name = "Form1";
            this.ResumeLayout(false);
        }
    }
}

由 FastAl 编辑

彼得,你摇滚!!!这几乎​​是我想要的。好吧,我还不能直接把物体扔给它;仅使用上述方法,没有填充 .Controls 属性,所以我得到了一个空白表格。此外,表单似乎必须由 GetNewHost 创建。幸运的是,我的 XMl-to-screen 例程实际上并没有创建容器,它只是返回一个平面的控件列表,我必须正确地重新设置它们的父级(SetChildren 子)。请注意我必须将它们添加到主机容器以使其了解它们的注释。现在它完美运行!

Public Module Main
    Public Sub Main()
        Dim FormSpecAsText As String = ...  read XML form def from file
        Dim Outfile As String = ... output file is in my project 

        ' Setup for Winforms platform
        Dim dsg As New DynamicScreenGenerator
        Dim ListOfControls As New PanelObjectList
        ControlFactoryLocator.AddService( _
            New PanelObjectFactoryWinFormBasicControls)
        ControlFactoryLocator.AddService(_
            New PanelObjectFactoryWinFormAppSpecificCtls)
        ControlFactoryLocator.AddService(_
            New PanelObjectFactoryWinFormFormEditorCtls)

        ' Deserialize FormSpecAsText into a flat list of Controls
        ListOfControls.AddRange( _
            dsg.BuildDSGLists(FormSpecAsText, ListOfControls).ToArray)

        ' setup for serialization to Code
        Dim hsm As New Host.HostSurfaceManager
        Dim hc As Host.HostControl = _
          hsm.GetNewHost(GetType(Form), Host.LoaderType.CodeDomDesignerLoader)

        ' Get main form that was created via GetNewHost, autosize it
        Dim HostUserControl = _
            CType(hc.DesignerHost.Container.Components(0), Form)

        ' Parent them properly, and add to host (top lvl ctls have parent="")
        SetChildren(HostUserControl, "", dsg, hc.DesignerHost.Container)
        HostUserControl.AutoSize = True

        ' write serialized version to a file in my project
        IO.File.WriteAllText(Outfile, _
          CType(hc.HostSurface.Loader, Loader.CodeDomHostLoader).GetCode("VB"))
    End Sub

    Sub SetChildren(ByVal Parent As Control, ByVal ParentName As String, _
           ByVal dsg As DynamicScreenGenerator, ByVal ctr As IContainer)
        For Each PO In (From p In dsg.POList Where p.Parent = ParentName)
            Dim child = CType(dsg.CTLList(PO), Control)
            ctr.Add(child, PO.Name) ' seem to have to add to container while 
             '  parenting them or .Controls isn't serialized and form is blank.
            Parent.Controls.Add(child)
            SetChildren(child, PO.Name, dsg, ctr)
        Next
    End Sub
End Module
于 2012-07-16T22:50:00.577 回答