Comment personnaliser la génération de code de InitializeComponent? Plus spécifiquement, comment puis-je post-traiter tout le code généré?

J’essaie de personnaliser la génération de code de Windows Forms Designer pour InitializeComponent . L’article MSDN “Personnalisation de la génération de code dans le .NET Framework Visual Designers” contient une section “Contrôle de la génération de code” qui explique les bases de la procédure.

J’ai suivi de près un exemple dans l’article ci-dessus:

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

Maintenant, je SomeForm ceci à ma forme SomeForm :

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

Le Concepteur de formulaires peut alors générer le code InitializeComponent suivant:

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

Notez que le commentaire // CODEDOM WAS HERE n’a pas été ajouté en tant que première ligne dans InitializeComponent , mais uniquement en tant que première ligne du bloc de code traitant des propriétés de l’object de formulaire lui-même.

Que devrais-je faire si je voulais être capable de modifier le CodeDOM généré de la méthode entière, et pas seulement de la partie qui traite d’un object spécifique?

Contexte: Pourquoi est-ce que je veux faire ça? Dans Windows Forms, si l’on souhaite une conversion de valeur flexible lors de la liaison de données, il est généralement nécessaire de s’abonner aux événements Format et Parse d’un object de Binding particulier. Je crée donc une sous-classe Binding spécialisée (appelons-la ConvertingBinding ) qui simplifie un peu ce processus.

À présent, le problème est que, lorsque les liaisons de données sont configurées dans le Concepteur Windows Forms, le code généré crée des instances de Binding . Cependant, je souhaiterais que le concepteur instancie plutôt ma sous-classe spécialisée. Mon approche actuelle consiste à laisser le concepteur d’abord créer une arborescence CodeDOM, puis parcourir cette arborescence et remplacer toutes les instanciations de Binding par des instanciations de ConvertingBinding .

Vous devez créer deux classes de Form . Premier Form avec DesignerSerializerAtsortingbute . Deuxième Form est le descendant de la première. Après cela, vous pouvez personnaliser InitializeComponent() pour le deuxième Form et ses contrôles ou composants. Pour cela, vous devez utiliser manager.Context pour obtenir tous les objects StatementContext et CodeStatementCollection contenant le code sérialisé des contrôles de Form .

Voici quelques étapes simples.
Inclure les bibliothèques:

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

Créez un nouveau formulaire et ajoutez DesignerSerializerAtsortingbute :

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

Créez CustomForm descendant de CustomForm et ajoutez-lui des contrôles ou des composants:

 class CustomForm1 : CustomForm { … } 

Ajoutez une méthode à CustomFormSerializer pour traiter CodeStatementCollection , par exemple:

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

Dans la méthode Serialize , utilisez cycle via 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; }