La POO appliquée aux winforms
Date de publication : 13/03/2006
Par
Stephane Eyskens (Autres articles)
Comme vous le savez tous, dotnet est une plateforme dont les langages sont 100% orientés objet. Pas une ligne de code
ne peut être écrite en dehors d'une classe. Conceptuellement parlant, et ceci est peut-être moins connu, nous pouvons appliquer
les mêmes mécanismes de POO au niveau de nos formulaires qu'au niveau de nos composants.
C'est ce que nous allons démontrer en utilisant un exemple simple.
Cet exemple a été réalisé avec Microsoft Visual C# Express Edition. Il est donc basé sur le framework 2. Pour une bonne compréhension
du tutoriel, le lecteur doit être familiarisé avec des notions telles que les windows forms, les DLL et l'orienté objet.
Je remercie les différentes personnes de l'équipe dotnet qui se sont chargés de la relecture de ce tutoriel. Parmi eux, nequib, Xo et Piotrek
1. Enoncé de l'exemple
1.1. Réalisation de notre composant.
1.2. Vue logique de notre composant
2. Scénario d'implémentation de nos windows forms
2.1. Extraits de code importants
3. Conclusion
4. Téléchargement
1. Enoncé de l'exemple
Pour démontrer la POO appliquée aux formulaires, nous allons réaliser une petite application simpliste gérant une liste de
formations à la carte dispensées par une école. Imaginons qu'il y ait deux types de formations :
- Les formations dont le coût de l'inscription est fixe
- Les formations dont le coût de l'inscription est variable en fonction du nombre de participants
L'exercice consiste juste à fournir à l'utilisateur une interface grâce à laquelle il pourra encoder
par exemple ceci
| Intitulé de formation |
Nombre d'heures |
Identifiant professeur |
| Oracle |
125 |
130 |
| Dotnet |
128 |
150 |
Une seule variante sera gérée à l'encodage, soit le coût de la formation sera fourni de manière forfaitaire par l'utilisateur, soit ce coût variera en fonction du nombre de participants. Dans ce cas, l'utilisateur fournira à la fois le coût par participant et le nombre de participants.
L'application gardera en mémoire les instances de formations encodées par l'utilisateur. Nous ne stockerons rien en base de données.
1.1. Réalisation de notre composant.
Nous savons que nous devons gérer des formations. La première chose que nous faisons est de chercher les points communs
de toutes les formations. Parmi ceux-ci, nous pouvons établir la liste (non exhaustive) suivante:
- Le libellé (toutes les formations disposent d'un libellé) Dotnet, Oracle...
- L'identifiant du formateur (tous les cours sont dispensés par un formateur)
- Le nombre d'heures.
Nous pourrions bien sûr trouver plus de points communs et étoffer notre composant pour gérer tous les cas de figure mais ce n'est pas
le but de cet article. Concentrons nous sur les mécanismes POO impliqués.
Identifions à présent, tout en restant fidèle à notre énoncé, les points qui diffèrent parmi les formations que nous désirons gérer:
- Le coût de la formation qui peut être soit forfaitaire, soit dépendant du nombre de participants
Nous pouvons dès lors conclure que nous avons à gérer de manière spécifique la manière dont le coût de la formation sera calculé.
Pour certaines formations, le nombre de participants ainsi que le coût par participant devront être connus, alors que pour d'autres, le prix forfaitaire suffira.
Sachant cela, nous pouvons désormais élaborer notre composant de la manière suivante:
1.2. Vue logique de notre composant
Notre composant est composé de quatre classes.
- La classe "formation" qui est une super classe abstraite contenant les propriétés communes et obligeant les classes dérivées
à implémenter la méthode "cout_formation". Cette méthode oblige les classes dérivées à implémenter leur propre mécanisme de calcul de coût.
- La classe "formation_cout_fixe" est une classe dérivée de "formation". Elle implémente son propre mécanisme de coût de formation consistant à simplement recevoir le coût forfaitaire en paramètre
- La classe "formation_cout_variable" est une classe dérivée de "formation". Elle implémente son propre mécanisme de coût de formation consistant
à multiplier le nombre de participants par le coût par participant.
-
La classe "gestion_formation" qui permet de stocker des instances de "formation_cout_fixe" et "formation_cout_variable" dans une ArrayList. C'est
cette instance qui sera le lien entre le composant et l'interface qui va l'utiliser.
Vous pourriez bien sûr créer d'autres classes dérivées qui répondraient à d'autres besoins en matière de coût de formation. Je le répète, le but de cet article n'est pas
de créer un composant gérant les formations mais bien de comprendre la logique objet que l'on peut appliquer au niveau des formulaires windows.
Notre DLL étant créée, on peut désormais l'utiliser avec tout type d'interface (web, windows forms, console...). Nous allons à présent voir comment il
est possible d'appliquer la même logique au niveau d'une interface windows forms.
2. Scénario d'implémentation de nos windows forms
Dans cette section, je vais décrire les étapes principales que j'ai suivies pour créer mon application. Vous pourrez visualiser le détail en
téléchargeant l'exemple.
Les étapes
- Création d'un projet "Windows Form en C#"
- Ajout de la référence vers notre composant
- Le formulaire principal créé par défaut par le projet doit être transformé en formulaire MDI. Pour ce faire, il faut modifier la
propriété "IsMdiContainer" et la mettre à "true"
- Ajouter les menus "Fichier -> quitter l'application" et "Formations -> Formation forfaitaire, Formation Variable, Liste. Ces menus
servent à ouvrir les fenêtres pour l'encodage des formations et pour les lister
Maintenant que notre formulaire MDI et nos menus sont prêts, nous allons créer nos autres formulaires en suivant la logique de notre composant. Nous allons d'abord commencer
par ajouter le formulaire qui correspond à la classe "formation" de notre composant. Il faut donc ajouter un formulaire à notre projet.
Lorsque ce formulaire est ajouté, nous devons créer les zones de texte communes, à savoir
- l'intitulé de la formation
- l'identifiant du professeur
- le nombre d'heures
Il faut donc ajouter trois contrôles de type "label" et 3 contrôles de type "textbox". Ne perdons pas de vue le fait que ces contrôles représentent les
caractéristiques communes de nos formations. Dès lors, nous allons modifier leur portée et les basculer en "protected".
Il faut modifier la propriété "Modifiers" de vos contrôles et la basculer en "Protected". Par défaut, le "Modifier" est positionné sur "Private". Le contrôle
n'est donc disponible que pour le formulaire courant. Le fait d'avoir modifé cette propriété rend ce contrôle utilisable par une classe dérivée.
Comme vous vous en doutez sûrement, nous devons à présent rajouter deux autres formulaires
- L'un correspondant à la classe "formation_cout_variable" de notre composant
- L'autre correspondant à la classe "formation_cout_fixe" de notre composant
Pour ce faire, il est nécessaire d'ajouter tour à tour ces formulaires. Selon l'IDE que vous utilisez, il vous sera soit possible d'ajouter les formulaires
en utilisant le template "Inherited windows form", soit vous devez ajouter un formulaire standard "Windows Form". Si vous devez opter pour la deuxième solution, veillez à changer l'héritage
par défaut qui est effectué lorsque vous créer un formulaire.
Vous devez en effet faire hériter vos deux nouveaux formulaires du formulaire "formation" que vous venez de créer. Par défaut, un formulaire hérite automatiquement de la classe "Form",
remplaçez "Form" par le nom de votre formulaire "formation". Si tout se passe bien, lorsque vous basculerez en mode "design", vous devriez aperçevoir les zones de textes crées au niveau du formulaire formation.
Voici un exemple de code mettant en exergue l'héritage du formulaire.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Formations;
namespace InterfaceFormations
{
public partial class formation_variable : InterfaceFormations.formation
{
public formation_variable()
{
InitializeComponent();
}
private void ajoutFormation_Click(object sender, EventArgs e)
{
try
{
gest.ajout_formation(intitule.Text,
int.Parse(id_prof.Text),
int.Parse(nb_heures.Text),
int.Parse(nb_part.Text),
float.Parse(cout_part.Text));
}
catch (gestion_formation_exception ajoutFrmEx)
{
MessageBox.Show(ajoutFrmEx.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
} |
Note: le formulaire "formation" étant supposé jouer le rôle de la classe "formation" de notre DLL, il doit logiquement être déclaré comme "abstract".
Selon l'IDE que vous utilisez, vous pourriez rencontrer un problème lorsque vous basculerez en mode "design" l'un de vos formulaires dérivés. Ceci est clairement un "bug" de l'IDE. Il est donc
vivement souhaitable de déclarer le formulaire en "abstract" à la fin du développement pour éviter ces désagréments. J'ai rencontré ce problème dans Visual C# Expression edition mais aussi dans Visual Studio .NET 2003.
Nous avons à présent "recréé" la même logique de programmation orientée objet que celle que nous avions adoptée lors de la réalisation de notre DLL car en effet, si nous répertorions nos
formulaires actuels et les liens qui les unissent, voici, shématiquement, ce que nous obtenons:
Les mécanismes d'héritage, de portée de membre au niveau des formulaires sont exactement les mêmes qu'au niveau d'une quelconque autre application. Ils sont très intéressants à connaître car, comme nous l'avons vu,
nous pouvons créer un "squelette" graphique de notre application contenant tous les champs communs à divers formulaires d'encodage et/ou d'affichage. Chaque formulaire d'encodage ou d'affichage pourra ensuite se spécialiser
selon ses propres besoins.
Ceci nous permet d'avoir une approche graphique structurée.
2.1. Extraits de code importants
Dans cette section sont affichés certaines portions de code importantes par rapport au type d'exemple mis en oeuvre.
Lorsque l'on charge un formulaire à partir du menu, dans un contexte MDI comme le nôtre, il faut charger la feuille comme suit:
formation_fixe f = new formation_fixe();
f.MdiParent = this;
f.Show(); |
Voici la classe formation de notre DLL.
using System;
using System.Collections.Generic;
using System.Text;
namespace Formations
{
public abstract class formation
{
protected string intitule;
protected int identifiant_prof;
protected int heures;
public formation(string arg_intitule,int arg_identifiant_prof,int arg_heures)
{
intitule=arg_intitule;
identifiant_prof=arg_identifiant_prof;
heures=arg_heures;
}
public string get_fiche()
{
return intitule + " " + identifiant_prof + " " + heures;
}
public abstract float cout_formation();
}
} |
Et voici la classe "formation_cout_variable", le lien entre "formation_cout_fixe" et "formation" étant le même, je ne l'incluerai pas ici.
using System;
using System.Collections.Generic;
using System.Text;
namespace Formations
{
public class formation_cout_variable : formation
{
private int nb_participants = 0;
private float cout_par_participant = 0.0F;
public formation_cout_variable(string arg_intitule, int arg_identifiant_prof, int arg_heures,
int arg_nb_part, float arg_cout_part)
: base(arg_intitule, arg_identifiant_prof, arg_heures)
{
nb_participants = arg_nb_part;
cout_par_participant = arg_cout_part;
}
public override float cout_formation()
{
return nb_participants * cout_par_participant;
}
}
} |
Je ne parlerai pas dans ce tutoriel de la manière dont les informations sont mémorisées. Je vous laisse découvrir
cela au niveau du code.
3. Conclusion
Nous avons vu qu'il est possible d'appliquer les mécanismes orientés objet au niveau de nos formulaires. Ceci apporte à mon sens un élément essentiel :
La possibilité de créer un squelette graphique de son application et par la même, éviter la redondance de contrôles
4. Téléchargement
 
Cet article est la propriété de www.developpez.com en tant qu'hebergeur ainsi que
celle de Stephaneey en tant que redacteur, ce texte est donc protégé par le code de la
propriété intellectuelle et est soumis à la réglementation en vigueur.
www.developpez.com ou son auteur se reserve le droit d'apporter des modifications
sans préavis. Vous pouvez utiliser cet article comme bon vous semble, faire un lien depuis
votre site Web, ou le copier en spécifiant l'auteur et la provenance (www.developpez.com)
Le non respect de cette règle equivaudrait à faire une contrefaçon. La responsabilité de
www.developpez.com, de l'un de ses membres, ou de la direction ne pourra etre engagé en cas
de destruction partielle ou totale des données ou de l'architecture système ou logicielle
inhérente à l'utilisation des ses logiciels. Les logiciels decrits ici sont la propriété de
leurs auteurs respectifs.
|