2012-04-22 7 views
9

Ich versuche, die Codegenerierung des Windows Forms-Designers für InitializeComponent anzupassen. Der MSDN-Artikel "Customizing Code Generation in the .NET Framework Visual Designers" enthält einen Abschnitt "Controlling Code Generation", der die Grundlagen erläutert, wie dies getan werden kann.Wie kann ich die Codegenerierung von InitializeComponent anpassen? Genauer gesagt, wie kann ich den gesamten generierten Code nachbearbeiten?

Ich habe aufmerksam verfolgen ein Beispiel, in dem obigen Artikel:

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

ich das jetzt Haken SomeForm meine Form auf:

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

Der Designer Forms könnte dann erzeugt den folgenden InitializeComponent Code :

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`) */ 
} 

Beachten Sie, dass die Comme nt // CODEDOM WAS HERE wurde nicht als erste Zeile in InitializeComponent hinzugefügt, sondern nur als erste Zeile des Codeblocks, der sich mit den Eigenschaften des Formularobjekts befasst.

Was müsste ich tun, wenn ich das generierte CodeDOM der gesamten Methode modifizieren wollte, und nicht nur des Teils, der sich mit einem bestimmten Objekt befasst?

Hintergrund: Warum möchte ich das tun? Wenn in Windows Forms eine flexible Wertkonvertierung während der Datenbindung gewünscht wird, muss normalerweise auf die Ereignisse Format und Parse eines bestimmten Objekts Binding abonniert werden. Also erstelle ich eine spezialisierte Binding Unterklasse (nennen wir es ConvertingBinding), die diesen Prozess ein wenig vereinfacht. Das Problem besteht nun darin, dass beim Erstellen von Datenbindungen im Windows Forms-Designer der generierte Code Instanzen von Binding erstellt. Ich möchte jedoch, dass der Designer stattdessen meine spezialisierte Unterklasse instanziiert. Mein derzeitiger Ansatz besteht darin, den Designer zuerst eine CodeDOM-Struktur erstellen zu lassen, dann diese Struktur zu durchlaufen und alle Instanziierungen von Binding durch Instanziierungen von ConvertingBinding zu ersetzen.

Antwort

11

Sie müssen zwei Form Klasse erstellen. Erste Form mit einer DesignerSerializerAttribute. Zweiter Form ist vom ersten Nachkommen abgeleitet. Danach können Sie InitializeComponent() für die zweite Form und seine Bedienelemente oder Komponenten anpassen. Dazu sollten Sie manager.Context verwenden, um alle StatementContext und CodeStatementCollection Objekte zu erhalten, die serialisierten Code von Form 's Kontrollen enthält.

Hier sind einige einfache Schritte.
Include-Bibliotheken:

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

neues Formular erstellen, und fügen Sie DesignerSerializerAttribute:

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

CustomForm Nachkomme Erstellen und einige Steuerelemente oder Komponenten, um es hinzuzufügen:

class CustomForm1 : CustomForm { … } 

Add-Methode zu CustomFormSerializer für Verarbeitung CodeStatementCollection, zum Beispiel:

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

In Serialize Verfahren Einsatzzyklus durch 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; 
} 
+0

Das ist fast, was ich will. Dies scheint ausreichend zu sein, um "bindende" Instanzen zu ersetzen; aber ich kann immer noch nicht auf die ganze Methode zugreifen, d. h. die ersten paar Zeilen und die letzten Zeilen in 'InitializeComponent'. – stakx

+1

@stakx: Die ersten Zeilen in 'InitializeComponent' bestehen immer aus' CodeVariableDeclarationStatement' Objekten. Wenn Sie Änderungen an einem dieser Objekte in 'CodeStatementCollection' vornehmen oder der Sammlung eine neue' CodeVariableDeclarationStatement' hinzufügen, werden alle diese Änderungen in den ersten Zeilen angezeigt. Alle anderen 'CodeStatement'-Zeilen erscheinen nach allen' CodeVariableDeclarationStatement'-Zeilen. – nempoBu4

Verwandte Themen