Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

NeuroCypher's Blog

{ Geoffrey DANIEL }

Life discovering...
Rien de bien mechant.


Actualités

  • EPITECH 5e annee

    Developpeur .NET mi-temps

[.NET] ICustomTypeDescriptor: Proprietes visibles d'un composant via le designer

Il m'arrive regulierement de creer des composant perso en .NET.

Le probleme auquel je suis souvent confronte est le suivant...
Il n'est pas rare qu'un composant personnel herite d'un composant tel qu'un Button ou un autre composant comportant multes proprietes.
Dans certains cas, le fait de modifier les proprietes du composant dont on herite peut deranger le bon fonctionnement du composant personnel car on n'a pas juge "necessaire" de surcharger telle ou telle methode.

Si on est le seul a utiliser le composant pas de probleme, mais si c'est une librairie utilisee au sein d'une equipe de dev, bonjour les degats.
Tout le monde a ses petites habitudes, "je veux que mon bouton soit en Flat", "Je veux un font Segoe UI..."

Afin de contrer ce probleme, on peut choisir quelles proprietes vont etre visibles via le PropertyGrid de l'IDE grace a l'interface ICustomTypeDescriptor (entre autre).
Evidemment les proprietes restent accessibles via le code, ce n'est donc pas une solution miracle, mais au moins les dev peuvent avoir une visu sur ce qu'ils peuvent utiliser via la PropertyGrid du designer. S'ils s'amusent apres a jouer avec le composant dans le code, c'est leur probleme.

J'ai remarque que ce sujet etait peu voire pas du tout documente en francais, ou en tout cas les rares existants restent tres vagues et decrivent l'interface ICustomTypeDescriptor en general et n'abordent donc pas ce point precis. Je tente donc de m'y coller du mieux que je peux.

Voici donc un composant "MyButton" qui herite de "Button"

namespace MyFuckinButton

{

  [ToolboxItem(true),

  ToolboxBitmap(typeof(Button)),

  Description("Un banal bouton")]

  public class MyButton : Button, ICustomTypeDescriptor

  {

    #region Variables

 

    /// <summary>

    /// _ pdc: collection des proprietes qui va etre consultee

    /// par le desginer property grid (entre autre, mais dans le

    /// cas present c'est ce qui nous interesse)

    /// </summary>

    private PropertyDescriptorCollection _pdc = null;

 

    #endregion

 

    // Constructor

    public MyButton()

    {

       InitializeComponent();

    }

 

    #region Properties

 

    /// <summary>

    /// ButtonText: Propriete ultra powerful rattachee a base.Text

    /// </summary>

    [Category("MyOnlyButtonProperty")]

    public string ButtonText

    {

      get { return base.Text; }

      set { base.Text = value; }

    }

 

    #endregion

 

    #region ICustomTypeDescriptor dependencies

 

    /// Rien de magique pour le moment

    /// Implementation typique des methodes de l'interface ICustomTypeDescriptor

 

    public TypeConverter GetConverter()

    {

      return TypeDescriptor.GetConverter(this, true);

    }

 

    public EventDescriptorCollection GetEvents(Attribute[] attributes)

    {

      return TypeDescriptor.GetEvents(this, attributes, true);

    }

 

    EventDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetEvents()

    {

      return TypeDescriptor.GetEvents(this, true);

    }

 

    public string GetComponentName()

    {

      return TypeDescriptor.GetComponentName(this, true);

    }

 

    public object GetPropertyOwner(PropertyDescriptor pd)

    {

      return this;

    }

 

    public AttributeCollection GetAttributes()

    {

      return TypeDescriptor.GetAttributes(this, true);

    }

 

    public PropertyDescriptorCollection GetProperties(Attribute[] attributes)

    {

      return GetProperties();

    }

 

    PropertyDescriptorCollection System.ComponentModel.ICustomTypeDescriptor.GetProperties()

    {

      return TypeDescriptor.GetProperties(this, true);

    }

 

    public object GetEditor(Type editorBaseType)

    {

      return TypeDescriptor.GetEditor(this, editorBaseType, true);

    }

 

    public PropertyDescriptor GetDefaultProperty()

    {

      return TypeDescriptor.GetDefaultProperty(this, true);

    }

 

    public EventDescriptor GetDefaultEvent()

    {

      return TypeDescriptor.GetDefaultEvent(this, true);

    }

 

    public string GetClassName()

    {

      return TypeDescriptor.GetClassName(this, true);

    }

 

    

    // C'est ici que tout se joue

    // C'est en effet cette methode qui est appelee afin de connaitre

    // les proprietes associees a notre classe

    public PropertyDescriptorCollection GetProperties()

    {

      // On ne va evidemment le generer qu'a la premiere demande

      if (_pdc == null)

      {

        // On recupere la collection des proprietes reelles de notre classe

        PropertyDescriptorCollection defaultProp = TypeDescriptor.GetProperties(this, true);

 

        _pdc = new PropertyDescriptorCollection(null);

 

        // Pour chaque Propriete contenu dans defaultProp

        foreach (PropertyDescriptor pd in defaultProp)

        {

          // A cet endroit la on va pouvoir ajouter les proprietes voulues

          // a notre nouvelle collection pdc

 

          // Dans cet exemple je choisis de n'afficher que les proprietes

          // de ma classe courante et de ne pas ajouter celle qui sont presentes

          // a cause de la classe dont on herite

          if (TypeDescriptor.GetProperties(typeof(Button)).Contains(pd) == false)

          {

              // Si je suis ici c'est que la propriete ne vient pas de la classe

              // J'ajoute donc l'element actuel a la collection

            _pdc.Add(pd);

          }

        }

      }

      return _pdc;

    }

 

    #endregion

 

    #region Designer dependencies

    // Rien de special, juste les choses "necessaires"

    // que j'ai choisi d'inclure aussi dans ce fichier pour que tout soit regroupe

    // afin de pouvoir diffuser la classe en entier

    private System.ComponentModel.IContainer components = null;

 

    protected override void Dispose(bool disposing)

    {

      if (disposing && (components != null))

      {

       components.Dispose();

      }

      base.Dispose(disposing);

    }

 

    private  void InitializeComponent()

    {

    }

 

    #endregion

  }

}

Ce qui nous permet d'obtenir dans la PropertyGrid de l'IDE :



Nous avons donc bien la propriete de notre classe sans voir celles de la classe Button.
Attention toutefois si vous avez des proprietes qui ont le meme Nom... Ce ne sera pas aussi simple...

A partir de la tout est possible grace au propriete du PropertyDescriptor et au GetProperties() de chaque objet.
Le type de selection s'arrete au meme endroit que l'imagination du dev.
Il est donc possible d'afficher seulement les proprietes/categories desirees, les proprietes d'un classe. Ou alors raisonner dans le sens contraire, ne pas afficher les proprites d'un classe, categorie, ou autre.
Je tiens tout de meme a souligner que cet exemple porte sur les proprietes mais bien d'autres choses sont interceptables via cette interface...

Voila j'espere que ca pourra servir a quelqu'un un jour et que c'est assez clair.
N'hesitez pas a faire des remarques, meme mauvaise, ca pourrait m'etre constructif par la suite.

Enjoy

Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :
Posted: dimanche 27 mai 2007 00:34 par NeuroCypher

Commentaires

emmaa a dit :

Ouais c'est clair, on dirait pas comme ça que t'as l'air patient avec tes petites choses, tout expliquer tout ca, ca donne presque ( ouais presque ) envie de faire du .NET.

# août 28, 2007 07:49
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Solution Template et Project Template dans Visual Studio par Atteint de JavaScriptite Aiguë [Cyril Durand] le il y a 23 minutes

- PocketIE et Assignation du SRC d'un Element IMG par Jerome Laban le il y a 1 heure et 15 minutes

- Conversion de fichiers RAW en fichier JPEG avec WPF par Perspective le il y a 1 heure et 51 minutes

- Mise à Jour du Moteur de Recherche des Arrêts de Bus de Montréal par Jerome Laban le il y a 2 heures et 35 minutes

- [WPF] XPSReader v0.2 par Blog Technique d'Audrey PETIT le il y a 3 heures et 36 minutes

- Entity Framework : providers Oracle, MySQL et PostgreSQL par Matthieu MEZIL le il y a 10 heures et 11 minutes

- [WPF] Nouvel article sur c2i.fr par Richard Clark le 09-06-2008, 17:33

- F# nouvelle CTP 1.9.6.2 (update) par Pierrick's Blog le 09-06-2008, 13:27

- La suite ...Proposition de collaboration rédactionnelle entre les communautés de développeurs et Microsoft France par LucasR le 09-05-2008, 17:45

- [Fun] Votre simulateur de vol avec Microsoft ESP par Julien Chable le 09-05-2008, 12:02