Développer un contrôle utilisateur (UserControl) en C#
Date de publication : 26/01/2006 , Date de mise à jour : 26/01/2006
Par
LEBRUN Thomas (Autres Articles)
Cet article vous apprendra comment créer et manipuler un contrôle utilisateur en C#.
I. Introduction
II. Création du UserControl dans Visual Studio
II-A. Création du UserControl
II-B. Utilisation des attributs
II-B-1. Attribut Category
II-B-2. Attribut Description
II-B-3. Attribut Browsable
II-B-4. Attribut DesignerSerializationVisibility
II-C. Associer une image à votre UserControl
III. Utilisation du UserControl
IV. Un peu plus loin
IV-A. Les événements
IV-B. Les SmartTags
IV-C. Les DesignerVerbs
V. Conclusions
VI. Téléchargements
I. Introduction
Le Framework .NET comporte un nombre important de contrôles utilisables dans vos applications. Cependant, il peut arriver que vous ayez besoin d'utiliser un contrôle qui est en fait, une combinaison de plusieurs contrôles de bases.
Pour cela, vous pouvez utiliser des contrôles utilisateurs.
Les Contrôles Utilisateurs (UserControls) sont des contrôles Dotnet que vous avez développés et que vous voulez réutiliser dans vos applications. On peut donc les assimiler à des contrôles personnalisés
Dans cet article, je vous propose une vue d'ensemble de ce qu'ils sont exactement ainsi que de leurs fonctionnalités diverses.
 |
Tous les exemples de cet article ont été réalisés avec Visual Studio 2005 Professionnal Edition, donc la version 2.0 du Framework .NET
|
II. Création du UserControl dans Visual Studio
II-A. Création du UserControl
Pour créer un UserControl, dans Visual Studio, vous avez 2 possibilités:
- faîtes un clic droit sur le nom de votre projet, choisissez "Add New Item" puis sélectionnez "User Control"
- ajoutez, à votre solution, un nouveau projet de type "Windows Control Library"
Voici ce que cela donne en image:
Et:
Vous vous retrouvez alors avec une fenêtre de ce type dans Visual Studio:
En fait, il s'agit d'une fenêtre Windows classique, mais sur laquelle il n'y a pas de bordures !
Sur ce formulaire, vous allez pouvoir utiliser toutes les capacités de Visual Studio, et en particulier le glisser/déposer de composants, pour créer votre composant personnalisé.
Tout au long de cet article, nous allons développer un contrôle d'authentification entièrement personnalisable: je vous laisse donc le soin d'architecturer l'interface graphique de celui-ci selon vos besoins et/ou idées, le tout étant d'avoir, si possible, quelque chose ressemblant à ceci:
Et voila !
La première partie, création du contrôle, étant maintenant terminée, nous allons donc voir comment l'utiliser dans nos applications.
 |
Une chose importante à savoir: bien que ce contrôle soit développé en C#, vous pouvez tout à fait l'utiliser avec n'importe quelle autre langage Dotnet (VB.NET, J#, etc...)
|
II-B. Utilisation des attributs
Si vous voulez pouvoir modifier certaines propriétés de vos UserControls dans la fenêtre "Properties" (Propriétés) de Visual Studio, vous devez utiliser les attributs.
Voici une liste, non exhaustive, des attributs qu'il vous est possible d'utiliser:
- Category
- Description
- Browsable
- DefaultValue
- DefaultEvent
Je vais détailler ici un peu plus certains de ces attributs.
II-B-1. Attribut Category
Cet attribut (Category)vous permet de définir dans quelle catégorie vous voulez que votre propriété soit placée. En effet, par défaut, la catégorie utilisée est "Misc" mais vous pouvez tout à fait modifier cela:
| Paramétrage de l'attribut Category | [Category("Configuration")]
public String Title
{
get
{
return this.gbLoginUserControl.Text;
}
set
{
this.gbLoginUserControl.Text = value;
}
} |
II-B-2. Attribut Description
L'attribut Description vous permet d'afficher, dans l'explorateur de propriétés, une petite description relative à la propriété (ou l'événement) sélectionné. Cela peut s'avérer très pratique si vous avez besoin de donner des informations, à l'utilisateur.
| Paramétrage de l'attribut Description | [Description("Le texte à afficher pour le nom d'utilisateur")]
public String LoginText
{
get
{
return this.lblLogin.Text;
}
set
{
this.lblLogin.Text = value;
}
} |
II-B-3. Attribut Browsable
Le dernier attribut dont je voulais vous parler est l'attribut Browsable. Celui-ci vous permet d'indiquer si, dans l'explorateur de propriétés, la propriété sélectionnée peut être modifiée. Dans le cas contraire, elle apparait comme grisée dans l'explorateur.
A noter que cet attribut prend en paramètre un booléen, et non pas une chaîne de caractère comme pour les autres attributs.
| Paramétrage de l'attribut Browsable | [Browsable(true)]
public String PasswordText
{
get
{
return this.lblPassword.Text;
}
set
{
this.lblPassword.Text = value;
}
} |
Voici le résultat que vous pouvez, par exemple, obtenir après avoir utilisé plusieurs de ces attributs:
| Code avec tous les attributs réunis | [Category("Configuration"), Browsable(true), Description("Le titre que vous voulez afficher")]
public String Title
{
get
{
return this.gbLoginUserControl.Text;
}
set
{
this.gbLoginUserControl.Text = value;
}
}
[Category("Configuration"), Browsable(true), Description("Le texte à afficher pour le nom d'utilisateur")]
public String LoginText
{
get
{
return this.lblLogin.Text;
}
set
{
this.lblLogin.Text = value;
}
}
[Category("Configuration"), Browsable(true), Description("Le texte à afficher pour le mot de passe")]
public String PasswordText
{
get
{
return this.lblPassword.Text;
}
set
{
this.lblPassword.Text = value;
}
} |
Ce qui donne:
Bien sûr, je ne vous l'ai pas dit avant, mais vous pouvez tout à fait combiner les attributs !
II-B-4. Attribut DesignerSerializationVisibility
Il est possible que vous soyez amené à developper un contrôle utilisateur qui utilise une collection comme propriété, jusque là, pas de problème.
Cependant, lorsque vous utilisez votre contrôle sur un formulaire Windows, et que vous ajoutez des éléments à cette collection, rien ne change dans le Designer (et rien n'apparaît dans le code d'initialisation du formulaire).
Pour que votre contrôle garde les valeurs qui ont été saisies dans le Designer, vous devrez utiliser l'attribut DesignerSerializationVisibility sur votre propriété:
| Attribut DesignerSerializationVisibility | List<String> list = new List<String>();
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public DisplayList
{
get
{
return list;
}
} |
Vous trouverez plus d'informations sur cet attribut à cette adresse.
II-C. Associer une image à votre UserControl
Vous avez la possibilité d'associer une image à votre UserControl, afin de le personnaliser encore plus et de le reconnaitre plus facilement dans la boite à outils.
Pour cela, commencez par inclure votre image à votre projet (clique droit sur le projet, puis sélectionner "Add" => "New Item") et, dans les propriétés, positionner "Build Action" sur "Embedded Ressource". Cela aura pour effet d'incorporer votre image dans la DLL de votre UserControl.
Ensuite, il ne vous reste plus qu'à ajouter un attribut à votre contrôle: l'attribut ToolboxBitmap.
L'attribut ToolboxBitmap permet d'associer une image à votre contrôle, image qui sera visible dans la boîte à outils. Voyons comment cela se passe:
| Association d'une image au contrôle | [ToolboxBitmap(typeof(LoginuserControl), "favicon.ico")]
public partial class LoginuserControl : UserControl
{
public LoginuserControl()
{
InitializeComponent();
}
} |
Le constructeur de ToolboxBitmap prend jusqu'à deux paramètres:
- le type qui définit l'assemblage dans lequel rechercher l'image du contrôle
- le nom de l'image
Le résultat est assez parlant de lui-même:
III. Utilisation du UserControl
Je vous l'ai dit un peu plus haut dans cet article, un UserControl, ce n'est qu'un simple contrôle personnalisé. Par conséquent, comme tous les contrôles que vous utilisez, il se trouve également dans votre boîte à outils.
S'il n'y apparait pas, vous devrez peut-être l'y ajouter vous-même. Pour cela, faites un clic droit sur votre boîte à outils, pius choisissez "Choose Items". Dans la boite de dialogue qui apparait, cliquez sur "Browse" puis allez chercher la DLL correspondant à votre UserControl:
Il ne vous reste plus qu'à valider pour voir ensuite votre contrôle apparaitre dans la boîte à outils:
faites maintenant un glisser/déposer de votre contrôle sur un formulaire: Visual Studio ajoutera automatiquement les dépendances nécessaires et placera le contrôle là où vous l'avez indiqué !
IV. Un peu plus loin
Vous vous dîtes surement que pour le moment, c'est pas mal mais vous trouvez ça léger, je me trompe ?
Rassurez-vous, jusqu'à maintenant, nous avons les principales bases de développement d'un contrôle personnalisé en C#. Nous allons maintenant étudier des concepts plus poussés qui vous permettront d'améliorer votre contrôle.
IV-A. Les événements
Comme tout contrôle .NET, votre UserControl possède des évènements prédéfinis (Load, Paint, etc...), jusque là, rien de bien nouveau.
Mais dans le cadre de notre article, nous avons développé un UserControl avec 2 boutons: un bouton de validation et un bouton d'annulation. Or, lorsque vous faites un glisser/déposer de votre contrôle sur un formulaire Windows, vous vous rendez compte que vous ne pouvez pas sélectionner un des deux boutons pour changer la valeur de son événement Click.
Pour remédier à cela, vous devez créer un (ou plusieurs) événements personnalisés, ce que nous allons voir tout de suite.
Pour que votre UserControl puisse utiliser votre événement, vous devez avoir au moins deux choses:
- un délégué pour l'événement
- le UserControl qui contient la déclaration de l'événement
Vous pouvez également utiliser une classe qui dérive de System.EventArgs, qui sera utilisée pour contenir les données relatives à l'événement (état, etc...).
Voyons cela par l'exemple: On commence par déclarer les délégués:
| Déclaration des délégués |
public delegate void ValidButtonClickHandler(object sender, EventArgs e);
public delegate void CancelButtonClickHandler(object sender, EventArgs e); |
Maintenant, déclarez les événements qui utilisent ces délégués:
| Déclaration des événements |
[Category("Configuration"), Browsable(true), Description("Evènement associé au bouton de validation")]
public event ValidButtonClickHandler BoutonValidClick;
[Category("Configuration"), Browsable(true), Description("Evènement associé au bouton d'annulation")]
public event CancelButtonClickHandler BoutonCancelClick; |
On créé ensuite les méthodes qui vont utiliser ces événements:
| Méthodes | protected virtual void OnValidButtonClick(EventArgs e)
{
if (BoutonValidClick != null)
{
BoutonValidClick(this, e);
}
}
protected virtual void OnCancelButtonClick(EventArgs e)
{
if (BoutonCancelClick != null)
{
BoutonCancelClick(this, e);
}
} |
Et voila, vous avez (presque) fini !
En effet, à partir de maintenant, tout ce qu'il vous reste à faire, c'est d'appeller vos méthodes dans l'événement Click (ou autre) de vos boutons:
| Evénement Click des boutons |
private void btValid_Click(object sender, EventArgs e)
{
OnValidButtonClick(e);
}
private void btCancel_Click(object sender, EventArgs e)
{
OnCancelButtonClick(e);
} |
Le résultat est directement visible lorsque vous utilisez votre UserControl sur un formulaire Windows:
IV-B. Les SmartTags
Les SmartTags sont une des nouveautés disponibles avec Visual Studio 2005 et le Framework .NET 2.0. Ils représentent une sorte de menu contextuel pour vos contrôles.
Et bien sachez que vous avez la possibilité de créer vos propres SmartTags pour votre contrôle.
Pour commencer, créer une classe UserControlActionList qui héritera de System.ComponentModel.Design.DesignerActionList: cette classe contiendra la liste des propriétés qui devront être ajoutées au SmartTag:
| Classe UserControlActionList | public class UserControlActionList : System.ComponentModel.Design.DesignerActionList
{
public UserControlActionList(IComponent component) : base(component)
{ }
public String Title
{
get
{
return ((LoginuserControl)this.Component).Title;
}
set
{
PropertyDescriptor property = TypeDescriptor.GetProperties(this.Component)["Title"];
property.SetValue(this.Component, value);
}
}
public String LoginText
{
get
{
return ((LoginuserControl)this.Component).LoginText;
}
set
{
PropertyDescriptor property = TypeDescriptor.GetProperties(this.Component)["LoginText"];
property.SetValue(this.Component, value);
}
}
public String PasswordText
{
get
{
return ((LoginuserControl)this.Component).PasswordText;
}
set
{
PropertyDescriptor property = TypeDescriptor.GetProperties(this.Component)["PasswordText"];
property.SetValue(this.Component, value);
}
} |
Dans cette classe, redéfinissons la méthode GetSortedActionItems qui nous permet de récupérer les actions définies par l'utilisateur.
| Redéfinition de GetSortedActionItems | public override System.ComponentModel.Design.DesignerActionItemCollection GetSortedActionItems()
{
System.ComponentModel.Design.DesignerActionItemCollection items = new System.ComponentModel.Design.DesignerActionItemCollection();
items.Add(new System.ComponentModel.Design.DesignerActionHeaderItem("Paramétrage"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("Title", "Définissez le titre du groupe de contrôles: ",
"Titre", "Titre du groupe de contrôle"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("LoginText", "Définissez le texte du champ Login: ",
"LoginText", "Texte du champ Login"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("PasswordText", "Définissez le texte du champ Password: ",
"PasswordText", "Texte du champ Password"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("LoginValue", "Définissez la valeur du champ Login: ",
"LoginValue", "Valeur du champ Login"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("PasswordValue", "Définissez la valeur du champ Password: ",
"PasswordValue", "Valeur du champ Password"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("PasswordChar",
"Définissez la caractère utilisé pour masquer le mot de passe: ", "PasswordChar", "Valeur du caractère pour le Password"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("TexteBoutonValid",
"Définissez le texte du bouton de validation: ", "TexteBoutonValid", "Texte du bouton de Validation"));
items.Add(new System.ComponentModel.Design.DesignerActionPropertyItem("TexteBoutonCancel",
"Définissez le texte du bouton d'annulation: ", "TexteBoutonCancel", "Texte du bouton d'Annulation"));
return items;
} |
A noter que cette méthode vous renvoit une DesignerActionItemCollection (une collection de DesignerActionItem ) et que vous avez à votre disposition, les DesignerActionItem suivants:
- DesignerActionHeaderItem: Permet d'afficher un nom de groupe de propriétés
- DesignerActionMethodItem: Permet d'appeler une méthode de l'ActionList
- DesignerActionPropertyItem: Permet d'afficher/éditer une propriété
- DesignerActionTextItem: Permet d'afficher une ligne de texte
Une fois que vous avez fait cela, il ne vous reste plus qu'à créer le SmartTag. Cela se fait en créant une classe (par exemple DesignerUserControl), qui hérite de System.Windows.Forms.Design.ControlDesigner.
Dans cette classe, nous allons redéfinir une propriété, ActionLists, qui renvoit une System.ComponentModel.Design.DesignerActionListCollection et qui nous permet de récupérer la liste de tous les éléments qui seront affichés dans le SmartTag.
| Redéfinition de ActionLists | public class DesignerUserControl : System.Windows.Forms.Design.ControlDesigner
{
public override System.ComponentModel.Design.DesignerActionListCollection ActionLists
{
get
{
System.ComponentModel.Design.DesignerActionListCollection collectionAction = new
System.ComponentModel.Design.DesignerActionListCollection();
UserControlActionList designerActionList = new UserControlActionList(this.Control);
collectionAction.Add(designerActionList);
return collectionAction;
}
}
} |
Et voila, vous avez terminé la création de votre SmartTag. Pour l'utiliser, c'est très simple: il vous suffit simplement d'ajouter l'attribut Designer à votre UserControl:
| Association du SmartTag au UserControl | [Designer(typeof(DesignerUserControl))]
public partial class LoginuserControl : UserControl
{
public LoginuserControl()
{
InitializeComponent();
}
} |
Et observez le résultat lorsque vous utiliser votre contrôle sur un formulaire Windows:
Avant de passer à la suite, voici quelques conseils pour la création de SmartTag:
- Ajouter l'attribut [Docking(DockingBehavior.Ask)] à votre UserControl vous permet d'afficher, dans le SmartTag, la commande "Dock in parent container"
- Vous devez rajouter une référence au namespace System.Design
- Vous devez ajouter les using correspondants à System.Windows.Forms.Design et System.ComponentModel.Design
IV-C. Les DesignerVerbs
Les DesignerVerbs sont des liens cliquables qui apparaissent dans l'explorateur de propriétés de Visual Studio, dans le menu contextuel du contrôle et dans le SmartTags.
Comme pour les SmartTags, pour créer un DesignerVerb, il faut créer une classe qui héritera de ControlDesigner. Là encore, nous allons surcharger une propriété, Verbs, qui renvoit une DesignerVerbCollection, et qui est utilisée pour avoir la liste de tous les DesignerVerb.
| Création d'un DesignerVerb | public class DesignerUserControl : System.Windows.Forms.Design.ControlDesigner
{
public override System.ComponentModel.Design.DesignerVerbCollection Verbs
{
get
{
DesignerVerbCollection collectionVerbs = new DesignerVerbCollection();
collectionVerbs.Add(new DesignerVerb("Afficher SmartTag",
new EventHandler(this.EventHandlerDisplaySmartTagVerbs)));
collectionVerbs.Add(new DesignerVerb("Visiter le site Web de l'auteur",
new EventHandler(this.EventHandlerVisitWebsiteVerbs)));
return collectionVerbs;
}
}
} |
Comme vous pouvez le voir, la collection DesignerVerbCollection n'est qu'un ensemble de DesignerVerb. Le constructeur de la classe DesignerVerb prend en paramètre deux choses:
- le texte du DesignerVerb, qui sera affiché dans le PropertyGrid, le menu contextuel et le SmartTag
- l'événement qui est lié au DesignerVerb, et qui surviendra lorsque l'on cliquera dessus
Dans mon cas, les événements sont très simples:
| Evénements liés aux DesignerVerb | private void EventHandlerDisplaySmartTagVerbs(object sender, EventArgs e)
{
MessageBox.Show("Vous avez cliquer sur Afficher SmartTag");
}
private void EventHandlerVisitWebsiteVerbs(object sender, EventArgs e)
{
System.Diagnostics.Process.Start("http://morpheus.developpez.com");
} |
Mais libre à vous de faire des choses plus complexes ;)
Enfin, pensez aussi à marquer votre contrôle avec l'attribut Designer:
| Association des DesignerVerbs au UserControl | [Designer(typeof(DesignerUserControl))]
public partial class LoginuserControl : UserControl
{
public LoginuserControl()
{
InitializeComponent();
}
} |
Voici le résultat en image:
 |
Si votre DesignerVerb n'apparaît pas dans le PropertyGrid, mais bien dans le menu contextuel et/ou le SmartTag, faites un clic droit sur le PropertyGrid et assurez vous que "Commands" est coché.
|
V. Conclusions
Grâce à cet article, vous avez pu vous rendre compte que développer un UserControl (Contrôle Utilisateur) s'avère extrèmement simple et rapide.
Vous avez également appris comment le personnaliser le plus possible, pour faire en sorte qu'il soit vraiment adapté à vos besoins, et le plus simple d'utilisation possible.
VI. Téléchargements
L'article au format PDF: Article
Les sources du contrôle d'authentification: Sources
 
|