IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

[C#]Modifier l'initialisation dans .design.cs


Sujet :

C#

  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut [C#]Modifier l'initialisation dans .design.cs
    Bonjour,

    Je sais utiliser les UITypeEditor, les TypeConverter et les ShouldSerializeProperty, mais je ne trouve pas où je peux accéder à la méthode qui permet au designer d'initialiser les propriétés dans le .design.cs de ma form.

    Pour donner un exemple inutile mais simple, si j'ai un contrôle qui dispose d'une propriété qui est un tableau d'entiers. Cette propriété est sérialisée comme suit dans la classe partielle:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
                this.bgTrackBar1.Tick1RelativePositions = new int[] {
            10,
            20,
            30,
            40,
            50,
            60,
            70,
            80,
            90,
            100};
    Comment faire pour que le designer écrive le tout en une ligne, comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                this.bgTrackBar1.Tick1RelativePositions = new int[] {10,20,30,40,50,60,70,80,90,100};
    Je l'ai dit, ça ne sert à rien dans cet exemple, c'est pour rester simple, je cherche juste où et comment intervenir pour les cas où au contraire ça m'est utile (remplacer l'initialisation par un appel à une méthode, à un constructeur avec paramètres etc)

    Merci d'avance,
    Claude

  2. #2
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    49
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 49
    Points : 21
    Points
    21
    Par défaut
    Bonjour à toi Claude.

    A vrai dire j'avais déjà du mal à comprendre la question... Mais alors avec l'exemple c'est encore pire, je n'arrive pas à comprendre ce que tu veux et où tu veux en venir.

  3. #3
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut
    Je vais tenter d'expliquer autrement.

    Quand tu places un contrôle dans une form (mettons "MaForm") et que tu modifies les propriétés par défaut de ce contrôle, pour chaque propriété modifiée, le designer ajoute les initialisations correspondantes dans le fichier "maForm.designer.cs".

    Par exemple, si tu places un textbox dans une form, tu obtiens ceci dans le fichier designer.cs:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
                // 
                // textBox1
                // 
                this.textBox1.Location = new System.Drawing.Point(234, 243);
                this.textBox1.Name = "textBox1";
                this.textBox1.Size = new System.Drawing.Size(100, 20);
                this.textBox1.TabIndex = 1;
    Tu vois qu'à chaque propriété "non par défaut", tu as une ligne.
    Par exemple, le fait de modifier la position du textBox produit la ligne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                this.textBox1.Location = new System.Drawing.Point(234, 243);
    Donc, "quelque part" il y a une méthode qui précise que pour une propriété de type "Point", le designer doit créer une ligne telle que celle-ci.

    Ce que je voudrais, c'est qu'avec certaines propriétés de mes contrôles, je puisse décider de la ligne qui va être ajoutée au lieu d'obtenir une ligne prévue "par défaut" pour ce type de propriété.

    Pour garder l'exemple du point, je voudrais par exemple que plutôt que d'obtenir
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                this.textBox1.Location = new System.Drawing.Point(234, 243);
    Le code généré automatiquement soit par exemple

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.textBox1.ChangeLocation(234,243);
    Or, je sais tester des valeurs par défaut complexes avec ShouldSerialize, je sais faire un convertisseur de type pour saisir en string dans la grille de propriété, je sais faire un éditeur de type, MAIS je ne trouve pas où et quoi surcharger pour que, par exemple, la propriété "Location" de mon contrôle ne produise plus la ligne par défaut dans .designer.cs, mais au contraire la ligne de mon choix.

    J'espère qu'expliqué comme ça, c'est plus clair

    Claude

  4. #4
    Membre à l'essai
    Inscrit en
    Juin 2009
    Messages
    49
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 49
    Points : 21
    Points
    21
    Par défaut
    Très clair oui. Mais si je ne m'abuse tout ça est simplement automatisé par VS et n'a rien à voir avec le framework même des winforms.

    Donc bien que je comprenne ton problème je ne saisis pas trop pourquoi tu parles de méthodes ou de surcharges.
    Je suppose pour ma part que ce sont des options à paramétrer dans VS... Quant à savoir si c'est possible et où elles sont alors là je sèche complétement donc je ne peux pas t'aider.

  5. #5
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Autant que je sache, le contenu de la méthode InitializeComponents n'est constitué que d'affectation de valeurs à des propriétés, et marginalement d'appels de méthodes (notamment pour spécifier la liste des contrôles d'un contrôle).
    Le designer doit juste savoir comment initialiser une instance de chaque type, pour l'affecter à la propriété, d'où le this.Location = new Point(bidule) que tu cites.

    Et je vois pas trop à quoi te servirait ce que tu cherches à faire ; la tendance dans la déclaration d'interfaces graphiques est d'oublier que c'est du code, et de ne caractériser les widgets que par l'ensemble de leurs propriétés. Comme HTML ou XAML, ou les bon vieux fichiers res de Win32, par exemple.
    ಠ_ಠ

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut
    Mais si je ne m'abuse tout ça est simplement automatisé par VS et n'a rien à voir avec le framework même des winforms.
    Le reste aussi est "automatisé".
    Tout ce que j'ai vu de VS jusqu'à présent, c'est qu'il repose aussi sur le framework et que l'esprit est plutôt de rendre tout accessible. Tout le designer, c'est du framework, je n'ai rien vu de spécifique à VS jusqu'à présent à ce niveau. Pour ce qui est de winform, j'ai posté ici parce que le code est créé dans la classe de la form.

    Je comprendrais mal qu'on puisse décider quand VS sérialise, qu'on puisse agir au niveau des grilles de propriétés, de l'éditeur lui-même, de tout ce qui concerne le designer, de l'intellisense, etc, mais que par contre on ne puisse pas "bêtement" modifier les lignes de codes générées automatiquement.

    Tu as peut-être raison, mais alors c'est dommage.

    Donc bien que je comprenne ton problème je ne saisis pas trop pourquoi tu parles de méthodes ou de surcharges.
    Parce que tout ce qu'il est possible de modifier dans le comportement du designer se fait de cette façon, et qu'on est en environnement objet.

    Je suppose pour ma part que ce sont des options à paramétrer dans VS
    Possible (si je ne sais pas comment on fait je ne peux pas prétendre savoir comment on ne fait pas) mais je vois mal une "option" consistant à lister l'intégralité des lignes de codes générées par VS. Et si c'était une option à paramétrer, ça voudrait dire que le code ne serait pas portable, puisque la moindre modif dans le designer par celui qui récupère les sources induirait de remettre les lignes générées automatiquement à leur aspect par défaut.

    Quant à savoir si c'est possible et où elles sont alors là je sèche complétement donc je ne peux pas t'aider.
    Tant pis, merci d'avoir essayé.

    Claude

  7. #7
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut
    Je n'avais pas vu la seconde réponse.

    Le designer doit juste savoir comment initialiser une instance de chaque type, pour l'affecter à la propriété, d'où le this.Location = new Point(bidule) que tu cites.
    Oui, je comprends ça pour les types primitifs, comme "int". Ca, ça pourrait être figé. Idem pour "class" (déjà ça devient plus dur).

    Mais justement, "Point", c'est une classe du framework,et le framework évolue. Je vois mal prévoir dans VS l'intégralité de toutes les classes existantes et leur initialisation, ce serait du reste contraire à l'esprit objet (ça devrait être indiqué dans la classe Point ou dans la propriété Location, et pas dans VS, tout comme ToString() est définit dans Point et pas dans une classe générique reprenant tous les Tostring possibles en fonction du type). Donc, VS devait générer une ligne identique pour toutes les propriétés de type "class".

    Or, Point dispose de 4 constructeurs et VS en choisis explicitement un avec deux paramètres. Où celà est-il précisé et comment reproduire ce comportement?

    Si je crée une classe publique similaire à Point avec 2 propriétés, i et j, et avec deux constructeurs, un sans paramètre et un avec deux paramètres, et que j'utilise cette classe comme type pour une propriété d'une autre classe, le designer ne me crée jamais la ligne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.mapropriete = new maclasse(0,1);
    mais il me crée une ligne du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.bgTrackBar1.myproperty = ((BgControls.maclass)(resources.GetObject("bgTrackBar1.myproperty")));
    Par contre, si je définis une propriété de type "Point", alors le designer est "correct". Moralité, j'en conclus que dans la classe "Point" il y a quelque chose qui indique au designer comment générer la ligne, ce dont ne dispose pas ma classe "comparable".

    Et je vois pas trop à quoi te servirait ce que tu cherches à faire ; la tendance dans la déclaration d'interfaces graphiques est d'oublier que c'est du code, et de ne caractériser les widgets que par l'ensemble de leurs propriétés. Comme HTML ou XAML, ou les bon vieux fichiers res de Win32, par exemple.
    Ce que je cherche à faire, c'est à ce que pour mes propres propriétés particulières d'un type non basique le designer me produise des lignes "plus propres" que ce qu'il ne fait par défaut, de pouvoir forcer l'appel d'un constructeur avec paramètres, et autres choses intéressantes.

    Se le designer utilise le constructeur Point avec 2 paramètres pour la propriété "Location" et qu'il ne le fait pas avec ma propriété basée sur une classe perso contenant aussi un constructeur avec 2 paramètres, j'ai pensé que ça voulait dire que "Point" précisait quelque part au designer comment générer les lignes d'initialisation.

    C'est ça que je cherche à faire également. Si MS a jugé utile de ne pas utiliser les générations automatiques par défaut pour ses propres classes, ça doit également être utile pour les autres, non?

    Du reste, puisqu'on parle de Point, j'ai un peu de mal avec ça : Le msdn indique que c'est une classe mais pointe sur les explications d'une structure. Reflector indique que c'est une structure, mais elle possède un constructeur sans paramètre et le msdn indique qu'une structure ne peut pas contenir de destructeur ni de constructeur sans paramètre. J'avoue m'y perdre un peu.

    Merci,
    Claude

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut
    Je pense être sur la piste.

    Lorsqu'on utilise un convertisseur de type, on a la possibilité de surcharger la méthode "ConvertTo" pour provoquer des transformations de type.

    J'utilisais le test sur if (DestinationType == typeof(string)) pour provoquer la conversion objet -> chaine affichée dans la grille de propriété.

    Mais en fait ça permet bien d'autres choses.
    Par exemple, DestinationType peut être InstanceDescriptor, ce qui permet d'agir lorsqu'on demande une instanciation de l'objet.

    Dès lors, j'ai trouvé ça dans le convertisseur de type de "Point" :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
      if (destinationType == typeof(InstanceDescriptor))
            {
                Point point2 = (Point) value;
                ConstructorInfo constructor = typeof(Point).GetConstructor(new Type[] { typeof(int), typeof(int) });
                if (constructor != null)
                {
                    return new InstanceDescriptor(constructor, new object[] { point2.X, point2.Y });
                }
            }
    Donc, si on tente de convertir vers un créateur d'instance, on cherche si on a un constructeur prenant 2 paramètres, et si oui on retourne un instanciateur avec les deux paramètres demandés.

    Donc j'ai bien l'impression que c'est ça qui impose l'utilisation du constructeur avec 2 paramètres, me reste à étudier le mécanisme de base

    Claude

  9. #9
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    OK, je vois mieux ce que tu cherches Il doit bien y a voir un mécanisme qui à une string associe un ensemble "constructeurs + arguments", puis qui ensuite écrive ce qu'il faut dans le Designer.cs.

    Point est en effet une struct, qui plus immutable, il est donc légitime et inévitable que ses constructeurs l'initialisent entièrement.

    Pour ce qui est des classes, par contre, l'habitude semble plutôt être d'appeler un constructeur vierge, puis d'affecter les propriétés une à une. Par exemple, quand on change le style des colonnes des datagridview, InitializeComponent déclare une variable de type DatagridViewCellStyle, modifie ses propriétés, puis affecte à la propriété "Style" de la colonne le style en question.

    Mais je ne vois toujours pas ton gain potentiel à surcharger tout ça. Le système actuel impose en effet de concevoir des composants qui peuvent s'initialiser propriété par propriété, contrainte pas si énorme.

    Ca me rappelle un truc rigolo : pour des raisons que j'ignore (mais qui tiennent probablement à ce que tu as vu par réflexion sur le ConvertTo de Point), les propriétés décimales ne sont pas simplement initialisées avec bidule.Truc = 51m mais avec bidule.Truc = new decimal(new int[] { 51, 0, 0, 0 }) C'est moche
    ಠ_ಠ

  10. #10
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut
    Il doit bien y a voir un mécanisme qui à une string associe un ensemble "constructeurs + arguments", puis qui ensuite écrive ce qu'il faut dans le Designer.cs
    Oui, c'est exactement ça que je cherche.

    Mais je ne vois toujours pas ton gain potentiel à surcharger tout ça. Le système actuel impose en effet de concevoir des composants qui peuvent s'initialiser propriété par propriété, contrainte pas si énorme.
    En fait, je cherche à "fignoler" mes contrôles perso.
    Faire un contrôle perso, c'est simple à la base, mais faire un contrôle perso qui soit aussi complet que ceux du framework de base, c'est déjà beaucoup plus complexe.

    Mes contrôles fonctionnent et je me suis attaqué aux détails (d'une part pour un résultat "pro" et d'autre part parce qu'en faisant ça on apprend plein de choses sur le framework".

    Exemples : Je savais empêcher l'utilisateur de redimensionner un controle dans une des dimensions, mais les poignées de redimensionnement restaient dans le designer : maintenant j'ai trouvé et résolu ce détail.

    J'avais des contrôles dans lesquels du texte était écrit, ben maintenant je sais créer des snaplines pour pouvoir aligner le contrôle non seulement via ses bords mais également depuis le texte écrit ou tout autre élément intérieur.

    Tous détails qui n'ajoutent rien au fonctionnement en exécution, mais qui rendent quand même le contrôle plus agréable en mode design. Et vu que tous ces contrôles sont destinés à devenir publics (selon mon habitude), ça me semble important.

    Tu vois le raisonnement?

    Maintenant, je voulais m'attaquer au code généré généré automatiquement par mes contrôles, pour voir s'il était possible de rendre ça plus propre que le code imbuvable produit parfois par le designer. Si on peut rendre ça "compréhensible" et plus "optimisé" (bien que je me méfie de ce mot), c'est toujours ça de pris, LOL.

    Point est en effet une struct, qui plus immutable, il est donc légitime et inévitable que ses constructeurs l'initialisent entièrement.
    Oui, mais j'ai tenté de créer une structure perso comme type d'une propriété, et je n'obtiens pas du tout le résultat obtenu avec Point. D'où ma recherche sur le convertisseur de type de Point, où je retrouve ce fameux constructeur renvoyé en tant qu' InstanceDescriptor. Jusqu'à présent, c'est le seul endroit où j'ai trouvé une trace de ça.

    Ca me rappelle un truc rigolo : pour des raisons que j'ignore (mais qui tiennent probablement à ce que tu as vu par réflexion sur le ConvertTo de Point), les propriétés décimales ne sont pas simplement initialisées avec bidule.Truc = 51m mais avec bidule.Truc = new decimal(new int[] { 51, 0, 0, 0 }) C'est moche
    Voilà, c'est exactement ça : c'est moche (même si c'est opérationnel).
    Tu me diras qu'il suffit de ne pas aller regarder mais bon....

    Ce n'est pas critique, mon code marche, mais comprendre est loin d'être inutile, et en plus j'aime comprendre

    Claude

  11. #11
    Membre éprouvé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    612
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Juin 2008
    Messages : 612
    Points : 1 050
    Points
    1 050
    Par défaut
    Suite :

    Bon, je viens de faire un test "bête", juste pour voir si ma piste est la bonne :

    1) Je crée une structure publique "mastruc" avec 2 int et un constructeur.
    2) Ensuite, je crée une propriété "myproperty" utilisant le type mastruc
    3) Je place mon contrôle sur la form, et j'obtiens le code "tordu" dont j'ai parlé créé par le designer

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
                this.bgTrackBar1.Myproperty = ((BgControls.mastruc)(resources.GetObject("bgTrackBar1.Myproperty")));
    4) J'écris les attributs forçant le typeconverter de Point:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [Serializable, TypeConverter(typeof(PointConverter))]
    Maintenant, je place mon contrôle sur la form, je compile, et j'obtiens le beau message d'erreur suivant :

    Impossible de générer le code pour MyProperty. L'erreur était : "PointConverter ne peut pas convertir BgControls.mastruc en System.ComponentModele.Design.Serialization.InstanceDescriptor
    et évidemment dans ma fenêtre .designer.cs je n'ai plus la ligne concernant MyProperty.

    Moralité, ça semble effectivement bien être le typeconverter qui détermine la création de la ligne dont on parle.

    Reste à comprendre exactement comment fonctionne les détails de ce mécanisme.

    Claude

    Edit :

    Test suivant:

    1) Je recopie tout le PointTypeConverter dans mon espace de nommage
    2) Je l'édite pour que ça corresponde à ma structure "mastruc" plutôt qu'à "Point" et je le renomme
    3) Je référence ce typeconverter
    4) Je place mon contrôle dans ma form, je tape <F6> : pas d'erreur.

    5) Je regarde dans ma fenêtre .designer.cs, et, surprise :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this.bgTrackBar1.Myproperty = new BgControls.mastruc(5, 6);
    J'ai donc réussi à forcer le designer à écrire ma propriété en faisant appel au constructeur de mon choix : ça semble fonctionner, ne reste qu'à comprendre les subtilités

    Claude

Discussions similaires

  1. Réponses: 3
    Dernier message: 28/02/2011, 14h11
  2. Modifier l'initialisation du fichier Designer.cs
    Par paulbenjamin.touzet dans le forum C#
    Réponses: 0
    Dernier message: 30/07/2010, 14h27
  3. Comment modifier les pages dans Sharepoint Designer
    Par rchalandon dans le forum SharePoint
    Réponses: 1
    Dernier message: 02/11/2007, 15h03
  4. [C#] Ajouter son propre composant dans Design de VS.Net
    Par yannick_sch dans le forum Windows Forms
    Réponses: 2
    Dernier message: 26/08/2004, 11h14
  5. Modifier un événement dans le code
    Par HT dans le forum Langage
    Réponses: 6
    Dernier message: 20/06/2003, 09h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo