begin process at 2008 05 16 17:51:03
1 173 622 membres
440 nouveaux aujourd'hui
13 972 membres club

Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum.
Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

COMPOSANT NON GRAPHIQUE QUI DÉTECTE SUR QUELLE FORM IL A ÉTÉ POSÉ


Information sur la source

Catégorie :Astuces Source .NET ( DotNet ) Classé sous : componentmodel, parentform, composant, idesignerhost, rootcomponent Niveau : Expert Date de création : 02/12/2005 Date de mise à jour : 26/10/2006 15:19:47 Vu : 6 426

Note :
9 / 10 - par 3 personnes
9,00 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (5)
Ajouter un commentaire et/ou une note


Description

Pour ceux qui ont déjà essayé de créer des composants ergonomiques, vous savez certainement qu'il en existe de plusieurs types :
- Les graphiques, qui ajoutent un contenu visuel à l'interface utilisateur, et qui dérivent de la classe UserControl. Par exemple, un bouton fait partie de cette catégorie de composants.
- Les non graphiques, qui ajoutent des fonctionnalités à votre logiciel, et qui la plus part du temps n'affichent rien de spécial. Le timer en est un bon exemple. Le NotifyIcon fait aussi partie de cette catégorie, et bien qu'il permette l'affichage d'une icône à côté de l'heure, il n'ajoute pas de contenu visuel à votre page.
- Et d'autres encore, comme les controles conteneurs, ...

Partons du principe que je veuille faire un composant qui, lorsque je modifie sa propriété "Couleur", modifie la propriété BackColor de ma form. Nous sommes d'accord : Le composant n'affiche rien de spécial dans la form, mais met simplement à jour une propriété de la form en elle même. Le composant a besoin de savoir sur qu'elle form il doit travailler, mais je n'ai pas envie de le spécifier à celui-ci quand je l'utilise : je considère que déposer un composant sur une form est assez explicite pour lui dire sur quelle form travailler.

En créant un UserControl, il est facile de récupérer la form parent. Ceci ce fait par un simple this.ParentForm. OR, dans le cas présent, nous voulons dériver de la classe System.ComponentModel.Component, puisque le composant n'est pas graphique. "this.ParentForm" n'est alors plus accessible ! Comment faire pour savoir sur quelle form a été posée notre contrôle ? Et bien pour répondre à cette question, je vous propose de regarder le code fourni ici.

Explications :
Tout se joue au moment du design ! Rien n'est détecté au moment de l'exécution !!! En fait, lorsque je dépose le composant que j'ai créé sur une form, le designer tente de récupérer toutes les valeurs des propriétés de mon composant (en tout cas celles dont une variable par défaut n'est pas définie, mais c'est une autre histoire), puis génère des lignes de code dans le InitializeComponent. Les lignes de code générées sont de type :
[NomDuComposant].[Propriété] = [ValeurRetournéeParLeGetDeLaPropriété];

Dans mon get, je vais alors chercher au moyen du DesignerHost (qui fournit un point d'accès au designer) un truc qui s'appèle le RootComponent. Je ne fais ceci que lorsque je suis en mode design. Ainsi, lorsque je pose mon composant ChangeCouleur (c'est con nom) sur ma form, le designer ajoute la ligne de code suivante dans le InitializeComponent :
            //
            // changeCouleur1
            //
            this.changeCouleur1.ParentForm = this;

Et voilà, c'est gagné ! La solution est plus que chelou, mais c'est celle qui est utilisée par exemple pour le timer, qui a semble-t-il besoin d'un handle vers la fenêtre sur laquelle il a été posé.

Source

  • using System;
  • using System.Collections.Generic;
  • using System.ComponentModel;
  • using System.Drawing;
  • using System.Data;
  • using System.Text;
  • using System.Windows.Forms;
  • using System.ComponentModel.Design;
  • namespace FreshNotes
  • {
  • public class ChangeCouleur : Component
  • {
  • private Form _ParentForm; // Page sur laquelle a été déposée le contrôle
  • /// <summary>
  • /// Permet de définir/récupérer le contrôle parent
  • /// </summary>
  • [Browsable(false)]
  • public Form ParentForm
  • {
  • // Accesseur en lecture
  • get
  • {
  • // Si l'on est en mode design, alors on demande au designer de définir la propriété ParentForm avec
  • // le this de la form contenant l'instance du composant.
  • if (this.Site.DesignMode)
  • {
  • IDesignerHost dh = (IDesignerHost)(this.GetService(typeof(IDesignerHost)));
  • if (dh != null)
  • {
  • object obj = dh.RootComponent;
  • if (obj != null)
  • {
  • _ParentForm = (Form)obj;
  • }
  • }
  • }
  • return _ParentForm;
  • }
  • // Accesseur en écriture
  • set
  • {
  • if (value != null) _ParentForm = value;
  • }
  • }
  • /// <summary>
  • /// Ma propriété couleur
  • /// </summary>
  • public Color Couleur
  • {
  • set {
  • if (_ParentForm == null) return;
  • _ParentForm.BackColor = value;
  • }
  • get { return _ParentForm.BackColor; }
  • }
  • /// <summary>
  • /// Constructeur
  • /// </summary>
  • public ChangeCouleur()
  • {
  • }
  • }
  • }
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.ComponentModel.Design;

namespace FreshNotes
{
    public class ChangeCouleur : Component
    {
        private Form _ParentForm; // Page sur laquelle a été déposée le contrôle

        /// <summary>
        /// Permet de définir/récupérer le contrôle parent
        /// </summary>
        [Browsable(false)]
        public Form ParentForm
        {
            // Accesseur en lecture
            get
            {
                // Si l'on est en mode design, alors on demande au designer de définir la propriété ParentForm avec
                // le this de la form contenant l'instance du composant.
                if (this.Site.DesignMode)
                {
                    IDesignerHost dh = (IDesignerHost)(this.GetService(typeof(IDesignerHost)));
                    if (dh != null)
                    {
                        object obj = dh.RootComponent;
                        if (obj != null)
                        {
                            _ParentForm = (Form)obj;
                        }
                    }
                }
                return _ParentForm;
            }

            // Accesseur en écriture
            set
            {
                if (value != null) _ParentForm = value;
            }
        }

        /// <summary>
        /// Ma propriété couleur
        /// </summary>
        public Color Couleur
        {
            set {
                if (_ParentForm == null) return;
                _ParentForm.BackColor = value;
            }
            get { return _ParentForm.BackColor; }
        }

        /// <summary>
        /// Constructeur
        /// </summary>
        public ChangeCouleur()
        {
        }
    }
}

Conclusion

Pour info, je n'ai pas trouvé cette astuce tout seul, mais j'ai trouvé un excélent article qui décrit la méthode en détail :
http://www.code-magazine.com/articleprint.aspx?quickid=0401091&printmode=true

Le gars (Ken Getz), a réussi à trouver l'astuce en décompilant le composant Timer.

On sent quand même ici une petite lacune du framework (le 1 comme le 2), et j'ai l'impression que même les mecs de Microsoft qui ont développé le Timer ont dû contourner cette lacune :D

NOTE IMPORTANTE : Merci de ne pas faire de commentaire du genre, je n'ai pas besoin de faire un composant qui modifie la couleur de ma form, je peux très bien manipuler le BackColor de ma form directement. Oui, OK, je suis d'accord avec ça, mais il n'empèche, dans certains cas, cette méthode s'avère utile. Par exemple, en ce moment, j'essaye de développer un composant non graphique qui ajoute un bouton Tray dans la barre de titre de la form sur laquelle il est posé. Et bien mon composant à besoin du ParentForm, et c'est ici que mon petit bout de code peut m'être utile ;-) Autre info, le dit composant ne peut pas dériver de UserControl, puisque je n'ajoute pas de contenu graphique dans le corps de la fenêtre mais plutôt dans la barre de titre, ce qui est totallement différent, puisqu'un UserControl ne peut pas s'y loger.

26 octobre 2006 15:19:47 :
Correction d'un petit bug avec l'ajout du test suivant : if (_ParentForm == null) return; Merci harpoceras ;)
  • signaler à un administrateur
    Commentaire de sebmafate le 02/12/2005 07:56:58 administrateur CS

    Bien... explications claires... code commenté... rien à redire ;)

  • signaler à un administrateur
    Commentaire de badrbadr le 02/12/2005 20:09:57

    c cool,
    c est pas inutile quand on prend le temps d y penser meme si au debut, quand j ai commencé ma lecture, je me disais: a quoi ca sert? (désolé :)
    mais quand j'ai terminé, c'est interessant

    en passant, j aimerais bien que tu m envoies ton programme qui ajoute un bouton dans la barre titre, ca m'interesse (tous les trucs graphiques speciales m interessent).
    utilise le systeme code source pour m envoyer un message :) merci d avance

    et salut

  • signaler à un administrateur
    Commentaire de yoannd le 05/12/2005 18:21:54

    Salut !

    Je vous remercie pour vos commentaires. Pour ce qui est du composant qui ajoute un bouton dans la barre de titre, tu peux aller ici :
    http://www.csharpfr.com/code.aspx?ID=34918

    Attention, le composant n'est pas fini, mais il peut te donner un apperçu de ce que je recherche.

  • signaler à un administrateur
    Commentaire de harpoceras le 26/10/2006 14:28:27

    Très utile.
    Le problème, c'est qu'en reprenant ce code tel quel, ça marche en design mais j'ai un plantage à l'exécution.
    Je remarque que le designer génère ces lignes :
    //
    // changeCouleur1
    //
    this.changeCouleur1.Couleur = System.Drawing.Color.Snow;
    this.changeCouleur1.ParentForm = this;

    Apparemment, l'ordre n'est pas bon. Si j'intervertis les lignes à la main, ça marche (affectation de la couleur après affectation de la form parente).
    Dans la classe, j'ai alors modifié la gestion de la propriété Couleur en ajoutant une ligne :

    public Color Couleur
            {
                set
                {
                    if (_ParentForm == null) return;
                    _ParentForm.BackColor = value;
                }
                get
                {              
                    return _ParentForm.BackColor;
                }
            }

    Là, ça marche bien.

    J'ajoute que je suis novice et qu'il y a peut-être qq chose que je n'ai pas compris...

  • signaler à un administrateur
    Commentaire de yoannd le 26/10/2006 15:15:19

    Salut !

    Effectivement, ce test manquait. Même si l'idée de base était de récupérer la form parente, une petite correction de bug ne se refuse jamais !

    a+

Ajouter un commentaire

Appels d'offres

Pub



CalendriCode

Mai 2008
LMMJVSD
   1234
567891011
12131415161718
19202122232425
262728293031 

VS Express FR Gratuit !

VS Express en français et 100% gratuit !

Téléchargements

Logiciels à télécharger sur le même thème :

Boutique

Boutique de goodies CodeS-SourceS