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 base. 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 deux possibilités :
- faites 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 voilà !
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 quel 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 :
[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ée. Cela peut s'avérer très pratique si vous avez besoin de donner des informations, à l'utilisateur.
[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.
À 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.
[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 :
[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é à développer 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'apparait 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é :
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 (clic droit sur le projet, puis sélectionnez « 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 boite à outils. Voyons comment cela se passe :
[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 boite à 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 boite à outils, puis 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 boite à 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énement personnalisé, 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 qui utilisent ces délégués
[Category(
"Configuration"
), Browsable(true), Description(
"Événement associé au bouton de validation"
)]
public
event
ValidButtonClickHandler BoutonValidClick;
[Category(
"Configuration"
), Browsable(true), Description(
"Événement associé au bouton d'annulation"
)]
public
event
CancelButtonClickHandler BoutonCancelClick;
On crée ensuite les méthodes qui vont utiliser ces événements :
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 voilà, vous avez (presque) fini !
En effet, à partir de maintenant, tout ce qu'il vous reste à faire, c'est d'appeler vos méthodes dans l'événement Click (ou autre) de vos boutons :
// On lance nos méthodes
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 :
public
class
UserControlActionList :
System.
ComponentModel.
Design.
DesignerActionList
{
public
UserControlActionList
(
IComponent component) :
base
(
component)
{
}
// Liste des propriétés à ajouter au SmartTag
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.
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 le 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;
}
À noter que cette méthode vous renvoie 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 renvoie 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.
public
class
DesignerUserControl :
System.
Windows.
Forms.
Design.
ControlDesigner
{
// On définit la liste des actions du SmartTag
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 voilà, vous avez terminé la création de votre SmartTag. Pour l'utiliser, c'est très simple : il vous suffit d'ajouter l'attribut Designer à votre UserControl :
[Designer(
typeof
(DesignerUserControl))]
public
partial
class
LoginuserControl :
UserControl
{
public
LoginuserControl
(
)
{
InitializeComponent
(
);
}
}
Et observez le résultat lorsque vous utilisez 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.
Enfin, voici un lien vers un autre article traitant des SmartTags : https://odelmotte.developpez.com/tutoriels/dotnet/controlesavances/?page=SmartTag (par Olivier Delmotte)
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 renvoie une DesignerVerbCollection, et qui est utilisée pour avoir la liste de tous les DesignerVerb.
public
class
DesignerUserControl :
System.
Windows.
Forms.
Design.
ControlDesigner
{
public
override
System.
ComponentModel.
Design.
DesignerVerbCollection Verbs
{
get
{
// On définit une collection de DesignerVerbs
DesignerVerbCollection collectionVerbs =
new
DesignerVerbCollection
(
);
// Ensuite, un à un, on ajoute des DesignerVerb à cette collection
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 :
private
void
EventHandlerDisplaySmartTagVerbs
(
object
sender,
EventArgs e)
{
MessageBox.
Show
(
"Vous avez cliqué 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 :
[Designer(
typeof
(DesignerUserControl))]
public
partial
class
LoginuserControl :
UserControl
{
public
LoginuserControl
(
)
{
InitializeComponent
(
);
}
}
Voici le résultat en image :
Si votre DesignerVerb n'apparait 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▲
Les sources du contrôle d'authentification : Sources