11

Windowsフォームデザイナのコード生成をカスタマイズしようとしていますInitializeComponent。MSDNの記事「.NETFrameworkVisualDesignerでのコード生成のカスタマイズ」には、これを行う方法の基本を説明する「コード生成の制御」セクションが含まれています。

私は上記の記事の例に厳密に従いました:

//using System.ComponentModel.Design.Serialization;

class SomeFormSerializer : CodeDomSerializer
{
    public override object Serialize(IDesignerSerializationManager manager,
                                     object value)
    {
        // first, let the default serializer do its work:
        var baseSerializer = (CodeDomSerializer)manager.GetSerializer(
                             typeof(Form).BaseType, typeof(CodeDomSerializer));
        object codeObject = baseSerializer.Serialize(manager, value);

        // then, modify the generated CodeDOM -- add a comment as the 1st line:
        if (codeObject is CodeStatementCollection)
        {
            var statements = (CodeStatementCollection)codeObject;
            statements.Insert(0, new CodeCommentStatement("CODEDOM WAS HERE"));
        }

        // finally, return the modified CodeDOM:
        return codeObject;
    }
}

今、私はこれを私のフォームに接続しますSomeForm

[DesignerSerializer(typeof(SomeFormSerializer), typeof(CodeDomSerializer))]
class SomeForm : Form { … }

その後、FormsDesignerは次のInitializeComponentコードを生成する可能性があります。

private void InitializeComponent()
{
    … /* (general setup code, such as a call to `this.SuspendLayout`) */ 

    // 
    // someButton
    // 
    … /* (someButton's properties are set) */

    // CODEDOM WAS HERE!
    // 
    // SomeForm
    // 
    … /* (form's properties are set) */

    … /* (general setup code, such as a call to `this.ResumeLayout`) */ 
}

コメントはの最初の行としてではなく、フォームオブジェクト自体のプロパティを処理するコードブロックの最初の行としてのみ// CODEDOM WAS HERE追加されていることに注意してください。InitializeComponent

特定のオブジェクトを処理する部分だけでなく、メソッド全体の生成されたCodeDOMを変更できるようにするには、どうすればよいですか?

背景:なぜこれをしたいのですか?Windowsフォームでは、データバインディング中に柔軟な値変換が必要な場合、通常、特定のオブジェクトのイベントFormatとイベントをサブスクライブする必要があります。そのため、このプロセスを少し単純化する特殊なサブクラス(これを呼びましょう)を作成しています。ParseBindingBindingConvertingBinding

ここで問題となるのは、Windowsフォームデザイナでデータバインディングを設定すると、生成されたコードがBinding;のインスタンスを作成することです。ただし、代わりに、デザイナーに自分の特殊なサブクラスをインスタンス化してもらいたいと思います。私の現在のアプローチは、設計者が最初にCodeDOMツリーを作成し、次にそのツリーをウォークして、のすべてのインスタンス化をのインスタンス化に置き換えることBindingですConvertingBinding

4

1 に答える 1

14

Form2つのクラスを作成する必要があります。最初FormDesignerSerializerAttribute。2番目Formは最初の子孫です。その後、InitializeComponent()2番目Formにカスタマイズして、そのコントロールまたはコンポーネントをカスタマイズできます。このために、のコントロールのシリアル化されたコードを含むmanager.ContextすべてStatementContextの オブジェクトを取得するために使用する必要があります。CodeStatementCollectionForm

ここにいくつかの簡単な手順があります。
ライブラリを含める:

using System.CodeDom;
using System.ComponentModel.Design.Serialization;
using System.Collections;

新しいフォームを作成して追加しDesignerSerializerAttributeます:

[DesignerSerializer(typeof(CustomFormSerializer), typeof(CodeDomSerializer))]
class CustomForm : Form { … }

CustomForm子孫を作成し、それにいくつかのコントロールまたはコンポーネントを追加します。

class CustomForm1 : CustomForm { … }

CustomFormSerializer処理のためにメソッドを追加しますCodeStatementCollection。次に例を示します。

private void DoSomethingWith(CodeStatementCollection statements)
{
    statements.Insert(0, new CodeCommentStatement("CODEDOM WAS HERE"));
}

メソッドSerializeの使用サイクルスルーmanager.Context

public override object Serialize(IDesignerSerializationManager manager,
    object value)
{
    //Cycle through manager.Context            
    for (int iIndex = 0; manager.Context[iIndex] != null; iIndex++)
    {
        object context = manager.Context[iIndex];

        if (context is StatementContext)
        // Get CodeStatementCollection objects from StatementContext
        {
            ObjectStatementCollection objectStatementCollection =
                ((StatementContext)context).StatementCollection;

            // Get each entry in collection.
            foreach (DictionaryEntry dictionaryEntry in objectStatementCollection)
                // dictionaryEntry.Key is control or component contained in CustomForm descendant class
                // dictionartEntry.Value is CodeDOM for this control or component
                if (dictionaryEntry.Value is CodeStatementCollection)
                    DoSomethingWith((CodeStatementCollection)dictionaryEntry.Value);
        }

        //Do something with each collection in manager.Context:
        if (context is CodeStatementCollection)
            DoSomethingWith((CodeStatementCollection)context);
    }

    // Let the default serializer do its work:
    CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
        GetSerializer(value.GetType().BaseType, typeof(CodeDomSerializer));
    object codeObject = baseClassSerializer.Serialize(manager, value);

    // Then, modify the generated CodeDOM:
    if (codeObject is CodeStatementCollection)
        DoSomethingWith((CodeStatementCollection)codeObject);

    // Finally, return the modified CodeDOM:
    return codeObject;
}
于 2012-11-07T09:39:26.523 に答える