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
etParse
d’un object deBinding
particulier. Je crée donc une sous-classeBinding
spécialisée (appelons-laConvertingBinding
) 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 deBinding
par des instanciations deConvertingBinding
.
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; }