Сериализовать уже созданный экземпляр WinForms.Form в VB или C# Sourcecode, как это делает IDE

У меня есть около 500 WinForms, которые динамически генерируются из файлов XML старым приложением. Я хотел бы автоматически преобразовать их в VB или C# код, который я могу редактировать в конструкторе.

Я могу сделать это вручную, что заняло бы вечность...

Или напишите приложение, которое загружает каждый XML, вызывает старый xml-to-winform-builder старого приложения, чтобы преобразовать его в законченную WinForm, и проверяет свойство каждого элемента управления и использует StringBuilder для генерации кода, который дизайнер проглотит. Что было бы нелегко в лучшем случае.

НО: я хотел бы использовать тот же код, который использует дизайнер. Это, я думаю, сэкономит мне время в угловых случаях.

Я хотел бы взять уже построенный объект WinForm с массивами элементов управления, заполненными дочерними элементами управления (созданными старым кодом xml-to-winform приложений), и выбросить его в тот же код, который IDE использует для сериализации разработанной формы. в CodeDom и верните список утверждений CodeDom, которые я могу сохранить на реальном языке. Как только я получу CodeDOM, я буду счастлив!

РЕДАКТИРОВАТЬ

Эта статья о Codeproject воплощает "концепцию" того, что я хочу сделать: начать с заполненной формы, преобразовать ее ("сериализовать") в код. Тем не менее, у него есть два недостатка: (1) он генерирует страницу.aspx с использованием шаблонов /stringbuilder, и именно там находятся свойства (хорошо для веб-форм, но winforms сериализует свойства в фактический файл.Designer.vb); (2) он делает все это с нуля. Я хочу повторно использовать рутины визуальной студии. Они позволяют вам делать это со многими вещами, например, сеткой свойств. Я просто ищу ссылку на статью (может быть, мой Google-фу был слишком слаб) или короткий пример кода из того, что кто-то уже сделал.

1 ответ

Решение

Так что это может или не может соответствовать вашим потребностям. У меня есть решение, но оно потребует от вас настройки рендеринга XML -> WinForms.

Это сильно зависит от использования этого проекта: http://ivanz.com/files/docs/designerhosting/create-and-host-custom-designers-dot-net.html

Скачав EXE (который является просто сжатой версией исходного кода с лицензионным соглашением) и соберите решение, у меня были некоторые проблемы со сборкой, пока я не удалил ссылки на библиотеку графиков (и связанные с ней вызовы из библиотеки Host). Почему библиотека Host должна рисовать графики, я не совсем уверен...

Затем я создал новый проект WinForms (не может быть консольным, потому что DesignSurface не может подключиться к событию перетаскивания). Ссылка на проекты Host и Loader из вышеуказанного проекта в вашем новом проекте winforms.

Здесь вам, несомненно, понадобится настроить существующий процесс. Объедините ваш существующий процесс так, чтобы он вписывался в этот тип построения форм, показанный для моей метки ниже:

        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
Другие вопросы по тегам