Vous êtes sur la page 1sur 20

2010

TD n 2 : Composants WinForms

Franck GIL
f.gil@odyssey-services.fr
23/09/2010

TD n 2 : Composants WinForms

INTRODUCTION

Nous allons voir tout ce que vous devez savoir sur les WinForms en crant ensemble (enfin surtout
vous !) un diteur demploi du temps simplifi.
Je sais que ce travail peut paratre long et difficile mais pour une fois a en vaut la peine. Suivez les
instructions jusquau bout, essayez de garder les mmes noms car il y aura des petits bouts de code
recopier. Essayez aussi de ne pas sauter les tapes.
Lancez Visual C# 2010 Express Edition et on y va !

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

UTILISER LES CONTROLES


2.1

HELLO WORLD

Commencez par crer une nouvelle application Windows en C#, nous lappellerons EmploiDuTemps.
Par dfaut, lassistant a cr une nouvelle fentre Form1 qui hrite de la classe Form. Celle-ci,
comme tous les composants dinterface, hrite de la classe Control. Chaque contrle peut contenir
des sous-contrles dans sa proprit Controls.
Nous allons ajouter un bouton dans notre fentre. Pour cela, allez dans la boite outils, trouvez le
contrle Button et glissez-le dans votre fentre. Maintenant, double-cliquez sur le bouton pour
gnrer automatiquement la mthode correspondant lvnement du clic.
Si vous regardez le code gnr par le designer dans InitializeComponent() (clic droit sur le nom de la
mthode puis Atteindre la dfinition) , vous verrez comment se construit une page. Vous pourrez
aussi voir comment la mthode button1_Click est branche sur lvnement :
this.button1.Click += new System.EventHandler(this.button1_Click);

Retournez dans le code de button1_Click et copiez le code suivant :


MessageBox.Show("Hello world");

Vous pouvez maintenant tester lapplication.

2.2

NOS DONNES

Les donnes de notre emploi du temps seront stockes dans une classe RendezVous. Cette classe
contiendra les attributs privs suivants :
_Texte : Informations sur le rendez-vous de type string,
_Debut : Date et heure de type DateTime,
_Duree : Dure en minutes de type int,
_Couleur : La couleur du rendez-vous sur le planning de type Color.
Prenez pour habitude de prfix le nom des attributs par un _, et de lenlever pour dfinir les
proprits de chaque attribut. Pour ajouter un fichier dans le projet, cliquez avec le bouton droit sur
le projet dans lexplorateur de solution. Pour faire propre, vous crirez des proprits pour tous les
attributs de la classe et vous utiliserez la documentation XML (tapez /// au dessus de la classe et des
proprits et laissez-vous guider).
Ensuite, vous crirez 2 constructeurs : un par dfaut et un autre prenant un paramtre pour chaque
attribut de la classe. De plus, la classe devra implmenter linterface Icloneable, qui vous obligera
dfinir la mthode clone comme ci-dessous :

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

public Object Clone()


{
return new RendezVous(_Texte,_Debut,_Duree,_Couleur);
}

Pour finir, vous surchargerez la fonction ToString() pour quelle retourne une chane de caractres
avec toutes les informations (sans aller la ligne) :
public override string ToString()
{
return this._Texte + " le " + this._Debut.ToLongDateString() + " "
+ this._Debut.ToLongTimeString()+ " et d'une dure de "
+ this._Duree.ToString() + " minutes";
}

Testez ensuite votre classe dans le code du bouton. Noubliez pas de manire gnrale de compiler
et tester votre code rgulirement.
private void button1_Click(object sender, EventArgs e)
{
RendezVous monRdv = new RendezVous();
monRdv.Texte = "Cours de .Net";
monRdv.Debut = DateTime.Now;
monRdv.Duree = 180;
monRdv.Couleur = Color.Red;
MessageBox.Show(monRdv.ToString());
}

2.3

UTILISATION DUNE LISTBOX

Nous allons maintenant affichez notre rendez-vous dans une liste. Pour cela, Ajoutez une
ListBox sur le formulaire. Comme la plupart des contrles affichant des donnes, la ListBox contient
une proprit Items qui permet dajouter des lments dans la liste. Dans le code du bouton, nous
allons afficher notre rendez-vous dans la ListBox en lajoutant sa liste des Items.

En ralit cest bien lobjet qui a t ajout la liste des Items. Cest uniquement pour laffichage que
la mthode ToString() a t appele. Malheureusement, elle ne sera pas rappele si tu modifies
lobjet dans la liste sans le raffecter.
Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

Il est possible daccder litem slectionn de deux faons :


En rcuprant la valeur de la proprit SelectedItem (qui peut tre null),
En rcuprant son index dans la liste Items avec la proprit SelectedItemIndex (qui peut
tre -1).
Dautres contrles fonctionnent globalement sur ce principe comme la ComboBox, TreeView et
ListView.

2.4

EDITION DUN RENDEZ-VOUS

Dans cette partie, nous allons crer un petit formulaire de saisie pour ajouter, modifier et supprimer
un rendez-vous. Pour cela, ajoutez votre formulaire les composants suivants :
une TextBox pour le texte (Name txtText),
un MonthCalendar pour la date (Name mcDebut et MaxSelectionCount 1),
une TrackBar pour la dure (Name tbDuree, TickFrequency 30, SmallChange 30,
LargeChange 30, Maximum 180 et Minimum 30)
un Label pour afficher la valeur slectionne dans la TrackBar (Name lblDuree),
une TextBox pour la couleur (Name txtColor et Enabled false),
un Button pour ouvrir linterface de slection dune couleur (Name btnColor et Text ),
un ColorDialog pour slectionner une couleur (Name cdColor),
un Button pour ajouter votre rendez-vous (Name btnAjouter et Text Ajouter),
un Button pour modifier votre rendez-vous (Name btnModifier, Enabled false et Text
Modifier),
un Button pour supprimer votre rendez-vous (Name btnSupprimer, Enabled false et Text
Supprimer),
un Button pour annuler la slection de votre rendez-vous (Name btnAnnuler, Enabled
false et Text Annuler).

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

Une fois le design du formulaire termin, nous allons surcharger tous les vnements ncessaires au
bon fonctionnement du formulaire. Dans un premier temps, nous allons crer une mthode qui
permet de vider les champs du formulaire pour le mettre dans un tat initial. Nous lutiliserons lors
de la cration de la page.
private void clearFields()
{
txtText.Text = "";
mcDebut.SelectionStart = DateTime.Today;
tbDuree.Value = tbDuree.Minimum;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
txtColor.BackColor = Color.White;
listBox1.SelectedItem = null;
btnAjouter.Enabled = true;
btnModifier.Enabled = false;
btnSupprimer.Enabled = false;
btnAnnuler.Enabled = false;
}

Nous allons modifier le comportement de la TrackBar pour rgler les dplacements du curseur de 30
en 30. Pour cela surchargez lvnement Scroll :
private void tbDuree_Scroll(object sender, EventArgs e)
{
tbDuree.Value = ((int)Math.Round((Double)tbDuree.Value / 30, 0)) * 30;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
}

Ensuite, nous allons permettre la slection de la couleur laide dune ColorDialog. Pour cela doublecliquez sur le bouton pour surcharger lvnement Click :
private void btnColor_Click(object sender, EventArgs e)
{
cdColor.ShowDialog();
txtColor.BackColor = cdColor.Color;
}

Le formulaire fonctionne dsormais correctement. Nous allons raliser maintenant les actions qui
vont permettre de grer lajout, la suppression et la modification dun rendez-vous. Pour raliser ses
actions nous allons surcharger plusieurs vnements de diffrents contrles :

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

Lvnement Click sur le bouton Ajouter :


private void btnAjouter_Click(object sender, EventArgs e)
{
RendezVous monRdv = new RendezVous();
monRdv.Texte = txtText.Text;
monRdv.Debut = mcDebut.SelectionStart;
monRdv.Duree = tbDuree.Value;
monRdv.Couleur = txtColor.BackColor;
listBox1.Items.Add(monRdv);
clearFields();
}

Lvnement SelectedIndexChanged sur la liste des rendez-vous :

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)


{
if (listBox1.SelectedItem != null)
{
RendezVous monRdv = listBox1.SelectedItem as RendezVous;
txtText.Text = monRdv.Texte;
mcDebut.SelectionStart = monRdv.Debut;
tbDuree.Value = monRdv.Duree;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
txtColor.BackColor = monRdv.Couleur;
btnAjouter.Enabled = false;
btnModifier.Enabled = true;
btnSupprimer.Enabled = true;
btnAnnuler.Enabled = true;
}
}

Lvnement Click sur le bouton Annuler :


private void btnAnnuler_Click(object sender, EventArgs e)
{
clearFields();
}

Lvnement Click sur le bouton Modifier :


private void btnModifier_Click(object sender, EventArgs e)
{
RendezVous monRendezVous = new RendezVous();
monRendezVous.Texte = txtText.Text;
monRendezVous.Debut = mcDebut.SelectionStart;
monRendezVous.Couleur = txtColor.BackColor;
monRendezVous.Duree = tbDuree.Value;
listBox1.Items[listBox1.SelectedIndex] = monRendezVous;
clearFields();
}

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

Lvnement Click sur le bouton Supprimer :


private void btnSupprimer_Click(object sender, EventArgs e)
{
listBox1.Items.RemoveAt(listBox1.SelectedIndex);
clearFields();
}

Flicitation ! Vous venez de crer votre premier formulaire, testez si toutes vos fonctionnalits
fonctionnent et passez la suite qui savre trs intressante.

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

CREATION DUN CONTROLE EMPLOI DU TEMPS

Cette partie, va vous montrez comment crer un contrle rutilisable permettant dafficher et de
manipuler un emploi du temps. Notre exemple reste limit, mais vous pourrez le personnaliser
souhait en y ajoutant de nouvelles fonctionnalits.

3.1

NOUVEAU CONTROLE

Ajoutez votre projet un nouveau contrle utilisateur que vous nommerez EditView. Il hrite de
UserControl. Commencez par y ajouter les attributs publics suivants :
NbJours : Nombre de jour afficher,
DebutJour : Premire heure afficher reprsente par un entier en minutes,
FinJour : Dernire heure afficher reprsente par un entier en minutes,
PremierJour : Premier jour afficher sur lemploi du temps reprsent par un DateTime,
Intervalle : Permet de dfinir des crneaux dans une journe. Il est reprsent par un entier
en minutes,
Marge : De type SizeF qui permet de dfinir une taille 2D,
Selection : De type RendezVous, permet de stocker le rendez-vous slectionn sur le
planning,
Items : contiendra les rendez-vous, il est de type ArrayList.
Nous allons chercher afficher lemploi du temps sous forme de grille. Pour cela, il va falloir dfinir la
largeur dun jour (une colonne) et la hauteur dune minute (une ligne). Il faut donc ajouter 2
proprits qui seront calcules en fonction des autres. Ces deux attributs seront prive, non
modifiable et de type float :
LargeurJour : La largeur totale moins la largeur de la marge, le tout divis par le nombre de
jours,
HauteurMinute : La hauteur totale moins la hauteur de la marge, le tout divis par le nombre
de minutes entre DebutJour et FinJour.
Tous ces attributs seront initialiss dans le constructeur du composant sauf Largeurjour et
HauteurMinute :
public EditView()
{
this.NbJours = 5;
this.DebutJour = 480;
this.FinJour = 1140;
this.PremierJour = DateTime.Today;
this.Marge = new SizeF(48, 32);
this.Selection = null;
this.intervalle = 30;
this.Items = new ArrayList();
InitializeComponent();
}

Une fois compil, tu peux ajouter ton contrle la


fentre.
Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

3.2

DESSINER AVEC GDI+

Nous allons maintenant afficher une grille qui prendra toute la place disponible (Width, Height)
moins la marge. Tout le code sera dans la classe EditView.

Pour cela, surchargez lvnement Paint :


private void EditView_Paint(object sender, PaintEventArgs e)
{
int i;
this.LargeurJour = (this.Width - Marge.Width) / NbJours;
this.HauteurMinute = (this.Height - Marge.Height) /(FinJour-DebutJour);
//Dessine les sparation des jours et le nom des jours
for (i = 0; i < NbJours; i++)
{
float width = Marge.Width + (i * LargeurJour);
string[] jour=PremierJour.AddDays(i).ToLongDateString().Split(' ');
e.Graphics.DrawString(jour[0].Replace(jour[0][0].ToString(),
jour[0][0].ToString().ToUpper()),
this.Font, new SolidBrush(Color.Black), new PointF(width, 0));
e.Graphics.DrawString(jour[1] + " " + jour[2] + " " + jour[3],
this.Font, new SolidBrush(Color.Black), new PointF(width, 14));
RectangleF monRect = new RectangleF(new PointF(width,Marge.Height),
new SizeF(new PointF(LargeurJour, this.Height -Marge.Height)));
e.Graphics.FillRectangle(new
System.Drawing.Drawing2D.LinearGradientBrush(monRect,Color.Gray
, Color.LightGray,
System.Drawing.Drawing2D.LinearGradientMode.Horizontal),
monRect);

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

e.Graphics.DrawLine(new Pen(Color.Black), new PointF(width,


Marge.Height), new PointF(width, this.Height));
}
//Dessine les horraires et les sparations des crnaux
for (i = DebutJour; i <= FinJour; i += intervalle)
{
float height = Marge.Height + ((i - DebutJour) * HauteurMinute);
int heure = i / 60;
int minute = i - (heure * 60);
e.Graphics.DrawLine(new Pen(Color.DarkGray), new
PointF(Marge.Width, height), new PointF(this.Width, height));
e.Graphics.DrawString(heure.ToString() + "H" + (minute != 0 ?
minute.ToString() : "00"), this.Font,
new SolidBrush(Color.Black), new PointF(0, height));
}
}

La surcharge de lvnement Paint propose le


paramtre PaintEventArgs, dans lequel vous
pouvez retrouver une rfrence sur un objet
Graphics qui permet de dessiner dans le
contrle.
On va afficher les sparateurs de jour et de
crneaux avec des lignes verticales pour les jours
et horizontales pour les crneaux laide de
Graphics.DrawLine.
Vous pourrez aussi utiliser Graphics.FillRectangle
pour dessiner les rectangles reprsentant les jours avec un dgrad vertical. Pour finir,
Graphics.DrawString permettra de dessiner les jours suivis de la date ainsi que les heures dans la
marge.
Quelques mots sur les types Pen et Brush :
Pen : Utilis pour dessiner des contours. On utilise en gnral new Pen(color) ou new
Pen(color,size).
Brush : Utilis pour remplir une forme. On utilise en gnral new SolidBrush(color) ou la
classe Drawing2D.LinearGradiantBrush pour les dgrads.

3.3

DOUBLE BUFFERING

Pour un raffichage fluide (viter les clignotements) il faut activer le double buffering. Ce mcanisme
permet de stocker le contenu du Graphics dans une image pour ne lafficher quune fois termin. On
vite ainsi tout clignotement. Vous devez juste ajouter le code suivant dans le constructeur du
contrle :
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);

Franck GIL
23 septembre 2010

10

11

TD n 2 : Composants WinForms

3.4

AFFICHER LES RENDEZ-VOUS

Comme vous avez pu le constatez, les rendez-vous seront stocks dans Items. On va les afficher dans
la grille sous forme de rectangle avec du texte lintrieur. Pour mettre en place cet affichage,
ralisez une mthode prenant en paramtre lobjet Graphics et un RendezVous :
private void AfficheRDV(RendezVous monRDV, Graphics g)
{
TimeSpan dateTemp = monRDV.Debut.Subtract(PremierJour);
if (dateTemp.Days >= 0 && dateTemp.Hours >= 0 && dateTemp.Minutes >= 0)
{
float x = Marge.Width + (dateTemp.Days * LargeurJour);
float y = Marge.Height + (((monRDV.Debut.Minute +
(monRDV.Debut.Hour * 60) - DebutJour) * HauteurMinute));
RectangleF monRect = new RectangleF(new PointF(x, y),
new SizeF(new PointF(LargeurJour,monRDV.Duree*HauteurMinute)));
g.FillRectangle(new System.Drawing.Drawing2D.LinearGradientBrush(
monRect, monRDV.Couleur, monRDV.Couleur,
System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal),
monRect);
g.DrawRectangle(new Pen(Color.Black), monRect.X, monRect.Y,
monRect.Width, monRect.Height);

g.DrawString(monRDV.ToString(), this.Font,
new SolidBrush(Color.Black) ,new PointF(monRect.X, monRect.Y));
}
}

Puis utiliser cette mthode dans lvnement Paint, en


ajoutant ce bout de code la fin de la surcharge:
//affiche les RDV
foreach (RendezVous monRdv in Items)
{
AfficheRDV(monRdv,e.Graphics);
}

Il y a une petite subtilit raliser au niveau de la mthode ToString() de lobjet RendezVous. En


effet, la chane de caractre quelle retourne nest pas optimise pour tre affiche dans un rendezvous dessin sur le planning. Redfinissez-la, laide du code suivant :
public override string ToString()
{
return this._Texte + "\n le " + this._Debut.ToShortDateString()
+ " " + this._Debut.ToShortTimeString();
}

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

Pour tester, vous pouvez arbitrairement ajouter des rendez-vous dans le constructeur dEditView, ou
bien modifier le code de notre ancien diteur. Dans le deuxime cas quelques modifications sont
apporter la surcharge de lvnement Click sur le bouton Ajouter:
private void btnAjouter_Click(object sender, EventArgs e)
{
RendezVous monRdv = new RendezVous();
monRdv.Texte = txtText.Text;
monRdv.Debut = mcDebut.SelectionStart.AddMinutes(editView1.DebutJour);
monRdv.Duree = tbDuree.Value;
monRdv.Couleur = txtColor.BackColor;
editView1.Items.Add(monRdv);
clearFields();
editView1.Invalidate();
}

Faites attention ! La date et lheure des rendez-vous doivent correspondre la grille, sinon cest
normal que cela ne marche pas. De plus, pour forcer le raffichage dun contrle on utilise la
mthode Invaidate() du contrle que lon veut raffich.

3.5

SELECTION DUN RENDEZ-VOUS

On va dsormais permettre lutilisateur de slectionner un rendez-vous avec la souris. Commencez


par crire une mthode dans la classe RendezVous qui retourne vrai si linstant pass en paramtre
(date et heure) est inclus dans le moment du rendez-vous :
public bool EstDedans(DateTime t)
{
DateTime dateFin = Debut.AddMinutes(Duree);
return t.CompareTo(Debut) >= 0 && t.CompareTo(dateFin) <= 0;
}

Dans la classe EditView ajouter les mthodes et surcharges suivantes :


Mthode QuelleHeureEstIl : retourne la date et lheure correspondant lendroit o lon a
cliqu sur la grille.
private DateTime QuelleHeureEstIl(PointF p)
{
float jour = (p.X - Marge.Width) / LargeurJour;
float minute = ((p.Y - Marge.Height) / HauteurMinute) + DebutJour;
if (jour >= 0 && minute >= 0)
{
return PremierJour.AddDays(Math.Floor(jour)).AddMinutes(minute);
}
return DateTime.MinValue;
}

Franck GIL
23 septembre 2010

12

13

TD n 2 : Composants WinForms

Mthode RecupRdv : retourne le rendez-vous se trouvant lendroit du clic, si aucun


rendez-vous ne se situe cet endroit la mthode retournera null.
private RendezVous RecupRdv(PointF p)
{
int i = 0;
bool trouve = false;
DateTime dateDuClick = QuelleHeureEstIl(p);
// le click eu lieu en dehors du planning
if (dateDuClick == DateTime.MinValue)
return null;
while (trouve == false && i < Items.Count)
{
if (((RendezVous)Items[i]).EstDedans(dateDuClick))
trouve = true;
else
i++;
}
if (trouve) return (RendezVous)Items[i];
else return null;
}

surcharge MouseDown : quand lutilisateur appuie avec le bouton droit de la souris, vous
allez rcuprer sa position (e.X, e.Y), et avec elle le rendez-vous concern, puis vous
laffectez lattribut Selection.
private void EditView_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Selection = RecupRdv(e.Location);
this.Invalidate();
}
}

Mthode AfficheRDVSelectione : permet de dessiner un rectangle rouge autour du rendezvous slectionn.

private void AfficheRDVSelectione(RendezVous monRDV, Graphics g)


{
TimeSpan dateTemp = monRDV.Debut.Subtract(PremierJour);
if (dateTemp.Days >= 0 && dateTemp.Hours >= 0 && dateTemp.Minutes >= 0)
{
float x = Marge.Width + (dateTemp.Days * LargeurJour);
float y = Marge.Height + (((monRDV.Debut.Minute +
(monRDV.Debut.Hour * 60) - DebutJour) * HauteurMinute));
RectangleF monRect = new RectangleF(new PointF(x, y),
new SizeF(new PointF(LargeurJour,monRDV.Duree*HauteurMinute)));

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

g.DrawRectangle(new Pen(Color.Red), monRect.X, monRect.Y,


monRect.Width, monRect.Height);
}
}

Note : On ne gre pas ici le fait quil puisse y avoir plusieurs rendez-vous en mme temps.
Il nous reste plus qu ajouter le code suivant la fin de la surcharge de lvnement Paint :
//affiche le RDV selectionn
if (Selection != null)
AfficheRDVSelectione(Selection, e.Graphics);

3.6

INTEGRATION DU FORMULAIRE DE SAISIE

A partir de maintenant nous disposons de tous les lments pour raliser lintgration complte du
composant EditView dans notre formulaire de saisie. Quelques modifications sont apporter aux
mthodes et aux surcharges des vnements du formulaire :
La surcharge de lvnement Click sur le bouton modifier :
private void btnModifier_Click(object sender, EventArgs e)
{
RendezVous monRdv = editView1.Selection;
int indice = editView1.Items.IndexOf(monRdv);
monRdv.Texte = txtText.Text;
monRdv.Debut = mcDebut.SelectionStart;
monRdv.Couleur = txtColor.BackColor;
monRdv.Duree = tbDuree.Value;
editView1.Items[indice] = monRdv;
clearFields();
}

La surcharge de lvnement Click sur le bouton supprimer :


private void btnSupprimer_Click(object sender, EventArgs e)
{
editView1.Items.Remove(editView1.Selection);
clearFields();
}

La mthode clearFields :
private void clearFields()
{
txtText.Text = "";
mcDebut.SelectionStart = DateTime.Today;
tbDuree.Value = tbDuree.Minimum;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
txtColor.BackColor = Color.White;
editView1.Selection = null;
btnAjouter.Enabled = true;

Franck GIL
23 septembre 2010

14

15

TD n 2 : Composants WinForms

btnModifier.Enabled = false;
btnSupprimer.Enabled = false;
btnAnnuler.Enabled = false;
editView1.Invalidate();
}

Par contre, si vous voulez que lors de la slection dun rendez-vous celui-ci saffiche dans le
formulaire, surchargez lvnement MouseDown du composant EditView mais cette fois-ci du ct
formulaire de saisie :
private void editView1_MouseDown(object sender, MouseEventArgs e)
{
if (editView1.Selection != null)
{
RendezVous monRdv = editView1.Selection;
txtText.Text = monRdv.Texte;
mcDebut.SelectionStart = monRdv.Debut;
tbDuree.Value = monRdv.Duree;
lblDuree.Text = "Dure: " + tbDuree.Value + " minutes";
txtColor.BackColor = monRdv.Couleur;
btnAjouter.Enabled = false;
btnModifier.Enabled = true;
btnSupprimer.Enabled = true;
btnAnnuler.Enabled = true;
}
else
clearFields();
}

3.7

DRAG&DROP DUN RENDEZ-VOUS

Microsoft, dans son Framework .Net, inclus nativement un mcanisme appel Drag&Drop. Il permet
de bouger la souris des objets dans une application, et mme entre diffrents programmes ! Par
exemple, on va faire en sorte de pouvoir dplacer nos rendez-vous sur notre emploi du temps, glisser
nos rendez-vous vers un calendrier dOutlook et vice-versa.
La premire chose faire est de fixer la proprit AllowDrop true. Les mcanismes de Drag&Drop
et Copier/Coller sont bass sur une structure DataObject. Elle permet de stocker plusieurs versions
de la donne transfre. Ainsi, si on dplace notre objet vers un logiciel de texte, il cherchera sil
contient du texte, si on le dplace vers un logiciel de dessin, il cherchera une image, etc. Nous
allons nous limiter notre type RendezVous et au type Texte.
Ajoutez la dclaration [Serializable] la classe RendezVous (au dessus de la dclaration de cette
classe) ainsi que les mthodes suivantes qui permettront la conversion :

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

public DataObject ToDataObject()


{
DataObject obj = new DataObject();
obj.SetData(DataFormats.Serializable, this);
obj.SetData(DataFormats.Text, Texte);
return obj;
}
public static RendezVous FromDataObject(IDataObject obj)
{
RendezVous rdv = obj.GetData(DataFormats.Serializable) as RendezVous;
if (rdv == null)
{
string str = obj.GetData(DataFormats.Text) as String;
rdv = new RendezVous(str, DateTime.Now, 60, Color.Green);
}
return rdv;
}

Pour plus de propret , jai dcid que lobjet ne sera rellement dplac qu la fin du
Drag&Drop. Nous allons crer un objet Tracker qui va garder en mmoire lobjet en cours de
dplacement, ainsi que sa future position. Voici le code de la classe RdvTracker qui correspond ce
mcanisme :
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
namespace EmploiDuTemps
{
class RdvTracker
{
public RendezVous rdv;
public DateTime Debut;
public RdvTracker(RendezVous rdv)
{
this.rdv = rdv;
this.Debut = rdv.Debut;
}
public static RdvTracker FromDataObject(IDataObject obj)
{
RendezVous rdv = RendezVous.FromDataObject(obj);
if (rdv != null)
{
return new RdvTracker(rdv);
}
return null;
}
}
}

Franck GIL
23 septembre 2010

16

17

TD n 2 : Composants WinForms

Ajoutez aussi dans EditView le champ private RdvTracker tracker = null;.Et enfin,
changez la surcharge de lvnement Paint pour quil soit affich. Dessinez-le de faon diffrente du
reste (Transparent par exemple). Noubliez pas quil commence tracker.Debut et non pas
tracker.Rdv.Debut.
Ajoutez ce bout de code la fin la surcharge de lvnement Paint :
//affiche le tracker
if (tracker != null)
AfficheRDVTracker(tracker, e.Graphics);

Puis crez la mthode qui va afficher le tracker :


private void AfficheRDVTracker(RdvTracker monTracker, Graphics g)
{
TimeSpan dateTemp = monTracker.Debut.Subtract(PremierJour);
if (dateTemp.Days >= 0 && dateTemp.Hours >= 0 && dateTemp.Minutes >= 0)
{
float x = Marge.Width + (dateTemp.Days * LargeurJour);
float y = Marge.Height + (((monTracker.Debut.Minute +
(monTracker.Debut.Hour * 60) - DebutJour) * HauteurMinute));
RectangleF monRect = new RectangleF(new PointF(x, y), new SizeF(new
PointF(LargeurJour, monTracker.rdv.Duree * HauteurMinute)));
g.DrawRectangle(new Pen(Color.FromArgb(30, Color.Black)),
monRect.X, monRect.Y, monRect.Width, monRect.Height);
g.FillRectangle(
new System.Drawing.Drawing2D.LinearGradientBrush(monRect,
Color.FromArgb(30, monTracker.rdv.Couleur), Color.FromArgb(30,
monTracker.rdv.Couleur),
System.Drawing.Drawing2D.LinearGradientMode.ForwardDiagonal),
monRect);
}
}

Enlve tous les vnements souris que tu avais sur le composant EditView, surcharge et recopie les
vnements suivants :
/// <summary>
/// La souris clique: on demarre le dplacement
/// </summary>
private void EditView_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
//Selectionne l'objet sur lequel on est
Selection = RecupRdv(e.Location);
if (Selection != null)// Lance le dplacement
DoDragDrop(Selection.ToDataObject(), DragDropEffects.Move |
DragDropEffects.Copy | DragDropEffects.None);
this.Invalidate();
}
}
/// <summary>
/// Dbut du dplacement: cration du tracker

Franck GIL
23 septembre 2010

TD n 2 : Composants WinForms

/// </summary>
private void EditView_DragEnter(object sender, DragEventArgs e)
{
tracker = RdvTracker.FromDataObject(e.Data);
}
/// <summary>
/// Dplacement en cours sur cet enploi du temps
/// </summary>
private void EditView_DragOver(object sender, DragEventArgs e)
{
//rcupre les coordonnes de la souris dans la fentre
Point loc = PointToClient(new Point(e.X, e.Y));
// Si le tracker existe
if (tracker != null)
{
//rcupre le curseur de copie si la touche Control est appuye ou
//si l'objet en cours de mouvement n'est pas dans lenploi du temps
if (((e.KeyState & 8) == 8 || !Items.Contains(tracker.rdv)))
e.Effect = DragDropEffects.Copy;
else if (loc.X < Marge.Width || loc.Y < Marge.Height)
e.Effect = DragDropEffects.None;
else
e.Effect = DragDropEffects.Move;
// on dplace le tracker mais pas l'objet qu'il contient
if (e.Effect==DragDropEffects.Move||e.Effect==DragDropEffects.Copy)
{
//gestion du chevauchement
DateTime date = QuelleHeureEstIl(loc);
int minute=((date.Minute/intervalle)*intervalle)+60*date.Hour;
if (minute > FinJour - tracker.rdv.Duree)
{
minute = FinJour - tracker.rdv.Duree;
}
date = date.Date.AddMinutes(minute);
RendezVous aComparer = new RendezVous(Selection.Texte, date,
Selection.Duree, Selection.Couleur);
bool seChevauche = false;
foreach (RendezVous rdv in Items)
{
if (rdv != Selection && rdv.SeChevauche(aComparer))
{
seChevauche = true; break;
}
}
if (!seChevauche)
{
tracker.Debut = date.Date;
tracker.Debut = tracker.Debut.AddMinutes(minute);
}
else
e.Effect = DragDropEffects.None;
}
Invalidate();
}
}

/// <summary>
/// On pose l'objet ici

Franck GIL
23 septembre 2010

18

19

TD n 2 : Composants WinForms

/// </summary>
private void EditView_DragDrop(object sender, DragEventArgs e)
{
if (tracker != null)
{
//Si en train de copier: on copie et on ajoute l'objet
if (e.Effect == DragDropEffects.Copy)
{
Selection = tracker.rdv.Clone() as RendezVous;
Items.Add(Selection);
}
// on affecte la nouvelle date (et heure)
Selection.Debut = tracker.Debut;
//on enlve le tracker
tracker = null;
Invalidate();
}
}
/// <summary>
/// Fin du dplacement: n'a pas eu lieu, ou est sorti de la fentre
/// </summary>
private void EditView_DragLeave(object sender, EventArgs e)
{
//on enlve le tracker
tracker = null;
Invalidate();
}

Vous avez du remarquez, que le dplacement du tracker entraine la vrification du chevauchement


de rendez-vous. Pour raliser ce mcanisme, vous devez ajouter la mthode suivante la classe
RendezVous :
public bool SeChevauche(RendezVous rdv)
{
return (Debut.CompareTo(rdv.Debut) <= 0 &&
Debut.AddMinutes(Duree).CompareTo(rdv.Debut) > 0) ||
(Debut.CompareTo(rdv.Debut) >= 0 &&
Debut.CompareTo(rdv.Debut.AddMinutes(rdv.Duree)) < 0);
}

Si vous avez bien fait votre travail, vous devez pouvoir raliser toutes ces oprations :
Slectionner un rendez-vous en lui cliquant dessus.
Dplacer un rendez-vous dans un emploi du temps en le glissant avec la souris.
Copier un rendez-vous dans un emploi du temps en le glissant avec la touche Control
enfonce.
Copier un rendez-vous dans un autre emploi du temps en le glissant avec la souris (mets
pour a un deuxime emploi du temps dans votre fentre).
Glisser du texte depuis un programme quelconque (Word par exemple) vers votre emploi du
temps.
Si vous avez Outlook, essayez aussi de glisser un rendez-vous dans les deux sens.

Franck GIL
23 septembre 2010

Vous aimerez peut-être aussi