3

古いアプリによって XML ファイルから動的に生成された約 500 の WinForms があります。これらを、デザイナーで編集できる VB または C# コードに自動的に変換したいと考えています。

私はそれを手作業で行うことができますが、それには永遠に時間がかかります...

または、各 XML をロードし、古いアプリの xml-to-winform-b​​uilder を呼び出して完全な WinForm に変換し、すべてのコントロールのプロパティを調べ、StringBuilder を使用してデザイナーが飲み込むコードを生成するアプリを作成します。これはせいぜい難しいでしょう。

BUT: デザイナーが使用するのと同じコードを使用したいと思います。これにより、コーナーケースで時間を節約できると思います。

私がやりたいことは、(古いアプリの xml-to-winform コードによって作成された) 子コントロールでいっぱいのコントロール配列を持つ、既に構築された WinForm オブジェクトを取り、設計されたフォームをシリアル化するために IDE が使用するのと同じコードでそれをスローすることです。 CodeDom に移動し、実際の言語で保存できるステートメントの CodeDom リストを取得します。CodeDOM を取得したら、満足です!

編集

この Codeprojectの記事は、私がやりたいことの「概念」を体現しています。完成したフォームから始めて、それをコードとして変換 (「シリアル化」) します。ただし、2 つの欠点があります。(1) テンプレート/stringbuilder を使用して .aspx ページを生成し、そこにプロパティがあります (Web フォームでは問題ありませんが、winform はプロパティを実際の .Designer.vb ファイルにシリアル化します)。(2)これをすべてゼロから行います。Visual Studio のルーチンを再利用したい。たとえば、プロパティ グリッドなど、多くのことでこれを行うことができます。記事へのリンクを探しているだけです (おそらく私の 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 から画面へのルーチンは、実際にはコンテナーを作成しません。適切に親を変更する必要があるコントロールのフラット リストを返すだけです (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 に答える