Vous êtes sur la page 1sur 115

C sharp

Monsieur RANDRIANOMENJANAHARY
Lala Ferdinand
Qu’est-ce c’est C# ?

Langage proposé par Microsoft, standardisé par ECMA
(European Computer Manufacturers
Association :Organisme européen de normalisation)
-Langage orienté objet
-Une partie évolue vers les langages de programmation
par composants
-Dérivé de C++ et de Java
-MFC (Microsoft Foundation Class:bibliothèque de classes
en C++) est remplacée par librairie .NET Framework

Combinaison entre la force de C++ et la simplicité de
Visual Basic

Cross Platform (multiplateforme)
Le langage C#
 Le C# est un langage à objet procédural
 Syntaxe très proche de C++ et Java
 C'est un langage très fortement typé
 Il est non déclaratif (pas d'en-tête)
 La bibliothèque est fortement structurée
-utilisation d'espaces de nommages,
-accès via la directive « using ».
 La procédure principale doit être une méthode
statique publique d'une classe
 Elle doit s'appeler « Main »
 Les bibliothèques utilisées doivent être
référencées dans le projet
 La syntaxe peut être simplifiée avec « using »
 Les entrées/sorties de base sont accessibles
via l'objet Console (espace de nommage
System)
Présentation
•Microsoft propose 4 langages
–C#, C++,VB.NET,ASP.NET
dont C# est le premier recommandé par Microsoft
Créer une application console C#
dans Visual Studio
Créer un projet
Ouvrez Visual Studio --> choisissez Créer un nouveau projet
Dans la fenêtre Créer un nouveau projet
-->Toutes les langues
--> C# dans la liste déroulante
--> Windows dans la liste Toutes les plateformes
--> Console dans la liste Tous les types de projet.

Après avoir appliqué les filtres de langue, de


plateforme et de type de projet
--> le modèle d'application console
--> Next
Dans la fenêtre Configurer votre nouveau projet
--> tapez ou entrez le nom du projet dans la zone Nom du projet
--> Next.
Dans la fenêtre Informations supplémentaires
--> .NET 6.0
--> Créer.
Créer l'application
Commencez par quelques mathématiques de base
sur les nombres entiers en C#.
Dans l'Explorateur de solutions, dans le volet de
droite
→ sélectionnez Program.cs pour afficher le fichier
dans l'éditeur de code

Dans l'éditeur de code,


→ remplacezle code "Hello World" par défaut qui
indique Console.WriteLine("Hello World!");.
Remplacez la ligne par le code suivant :
int a = 42;
int b = 119;
int c = a + b;
Console.WriteLine(c);

Pour créer et exécuter votre application


--> appuyez sur F5 ou sélectionnez la flèche verte à
côté du nom Calculatrice dans la barre d'outils
supérieure.
Une fenêtre de console s'ouvre et affiche la somme
de 42 + 119, soit 161.
Éléments syntaxiques
Majuscules <> minuscules (case sensitif)
Les instructions se terminent par ;
les espaces de noms dont déclarés par using
// ou /// indique que le reste de la ligne est un
commentaire
/* indique un début de commentaire
*/ indique une fin de commentaire
un identificateur doit commencer par une lettre
ou _
Premier programme
// Introduit les fonctionnalités de System :
using System;
// Classe de l'application :
class MonApp
{
// Fonction principale :
public static void Main()
{
// Équivalent de System.Console.WriteLine:
Console.WriteLine("Hello World!");
}

}
Les types C#
 Les types fournit par C# :
–bool (booléens),
–char (caractère Unicode 16 bits),
–string (chaîne de caractères Unicode),
–types intégraux non signés (byte, ushort, uint,
ulong),
–types intégraux signés (sbyte, short, int, long),
–types flottants (float, double),
–currency (128 bits, pour les montants),
–object (type de base de tous les objets),
–void (type vide, pour les procédures).
Type Classe Description Exemple
bool System.Bool Booléen (vrai ou faux : true ou true
false)
char System.Char Caractère Unicode (16 bits) (ou 'A' 'λ' 'ω'
plus précisément, une unité de
code (code unit) Unicode

sbyte System.SByte Entier signé sur 8 bits (1 octet) -128


byte System.Byte Entier non signé sur 8 bits (1 255
octet)
short System.Int16 Entier signé sur 16 bits -129
ushort System.UInt16 Entier non signé sur 16 bits 1450
int System.Int32 Entier signé sur 32 bits -100000
uint System.UInt32 Entier non signé sur 32 bits 8000000
long System.Int64 Entier signé sur 64 bits -2565018947302L
ulong System.UInt64 Entier non signé sur 64 bits 8000000000000L
float System.Single Nombre à virgule flottante sur 3.14F
32 bits
double System.Double Nombre à virgule flottante sur 3.14159
Tableau à une dimension
int[] t; // référencé pas encore alloué
int[] t1, t2; // référencés pas encore alloués
t1 = new int [3]; // allocation
int[] t3 =new int[3]; //référencé et alloué
t2 = new int [] {5,3,1}; //allocation et initialisation
Console.Write(t2[0]); // affiche 5
Console.Write(t2.Length); // affiche 3
Array.Sort(t2); // tri le tableau
t2.CopyTo(t1,0); //copie t2 dans t1 depuis t2[0]
t3 = t2; // t3 et t2 référence le même tableau
Tableau à n dimensions

int[,] tn, tn1; // référencés pas encore alloués


tn1= new int [2,3]; // allocation
int [,] tn2 =new int[2,3]; //référencé et alloué
tn = new int [,] {{5,3,1}, {2,4,6}}; // initialisation
Console.Write(tn[1,0]); // affiche 2: col n°0, ligne n°1
Console.Write(tn.GetLength(0)); // affiche 2
tn1 = (int[,])tn.Clone(); //copie tn dans tn1
Déclaration des variables
int i = 2;
long l = 3L;
float f = 2.12f;
double d = 3.14D;
char c = 'A';
string s = "Hello World!\n";
bool b = true;
int tab1[] = new int[3] { 7, 9, 42 };
tab1[0] = 2;
long tab2[,] = new long[5,4];
tab2[2,3] = 5L;
object o = new int();
Les structures
Définition
-Structure est le type de données de type valeur qui
représente les structures de données.
-Il peut contenir un constructeur paramétré, un
constructeur statique, des constantes, des champs,
des méthodes, des propriétés, des indexeurs, des
opérateurs, des événements et des types
imbriqués.
Les structures
// Définition d'une structure :
struct Livre
{
public string nom;
public string auteur;
public string editeur;
// Possibilité de définir des méthodes (cf. classes)
// Moins souple que les objets (pas d'héritage, stockage par valeur)
}
// Utilisation des structures :
Libre l;
l.nom = "L'Odyssée";
l.auteur = "Homère";
Valeurs et références
 Les types peuvent être des valeurs ou des
références
 Les objets de type valeur :
–dérivent de System.ValueType,
–sont dupliqués lors des affectations,
–sont allouables directement sur la pile
 Les objets de type référence :
–ne sont pas dupliqués lors des affectations,
–doivent être alloués dynamiquement.
•Les types valeurs :
–types simples du langage,
–structures.

•Les types références :


–string, object, tableaux,
–classes utilisateur.

•Le type string n'est pas modifiable :


–fiable mais peu performant,
–utilisation de la classe System.Text.StringBuilder.
Transtypages

// Transtypages directs :
double d = 2;
int i = (int) d; // Conversion en type int
// Lance une exception en cas d'échec.
// Transtypage de références :
object o = "Hello World!\n";
// Attention, les chaînes de caractères sont des
références :
string s = o as string;
// Réinterprétation de référence.// Renvoie null en cas
d'échec.
Les tests
if (i == 2)
// Cas si i vaut 2.
else
if (i != 5)
{
// Cas si i est différent de 5.
}
else
if (i >= 7)
{
// Cas si i est supérieur ou égal à 7.
}
else
{
// Autres cas.
}
Les branchements conditionnels
switch (i)
{
case 1:
case 2:
// Traitement si i vaut 1 ou 2.
break; // Obligatoire.

case 5:
// Traitement si i vaut 5.
goto default; // Saut à une autre étiquette.

Default:
// Traitement pour les autres cas.
break;

}
// Contrairement au C, switch fonctionne aussi avec les
chaînes.
La boucle do
do{
// Code exécuté une fois au moins, puis tant
// que la condition exprimée par la ligne while :

} while (i < 7);


do
{
// Rupture de séquence :
if (j == 2)
continue; // Saut direct à la condition.
if (k > 10)
break; // Sortie de boucle.

} while (i < 10);


La boucle while
// Contrairement au do, le test est effectué en premier :

while (i < 7)
{
// Traitement effectué tant que i est inférieur à 7.
// Les ruptures de séquences break et continue sont
// toujours utilisables.
}
La boucle for
// Boucle classique « à la C++ ».
// Déclaration et initialisation de la variable muette,
// test de condition de boucle, opération //d'incrémentation.
// La condition est évaluée en premier (comme
// pour while) :
for (int i = 0; i < 10; ++i)
{
// Code exécuté tant que i < 10, en partant de i = 0 et
// avec incrémentation de i à chaque itération.
}
// La variable muette i n'est plus définie après la boucle.
Les itérations foreach
string[] tab = new string[5];
tab[0] = "chaîne 1";

tab[4] = "chaîne 5";
// Itération sur l'ensemble des données du conteneur tab :

foreach (string s in tab)


{
// Code exécuté pour chaque valeur contenue dans tab.
// La valeur est stockée dans la variable muette s
// déclarée dans l'instruction foreach :
Console.WriteLine(s);
}
// Le conteneur énuméré doit implémenter IEnumerable
Les sauts
foreach (string n in noms)
{
foreach (string p in prenoms)
{
if (n == "Dupont" && p == "Jean")
goto trouve;

}
}
// Traitement si non trouvé
goto fin;
trouve:
// Traitement si trouvé
fin:
Les exceptions
•La gestion des erreurs de .NET est basée sur les
exceptions
•Les exceptions doivent toutes dériver de la classe
de base System.Exception
•Les exceptions contiennent les informations sur
l'erreur et son contexte
•La syntaxe utilisée est semblable au C++
•Disponibilité d'un bloc finally pour la libération des
ressources
Les exceptions
try{
// Code exécuté sous le contrôle du try.
}
catch
{
// Récupération des exceptions.
}
finally
{
// Traitement de fin de bloc try.
// Exécuté qu'il y ait eu une exception ou non.
// Attention, n'est pas exécuté si l'exception n'est
// traitée par aucun bloc catch !
}
Les exceptions
try
{
// Lancement de l'exception :

}
// Récupération de l'exception :
catch (IO.FileNotFoundException e)
{
Console.WriteLine(e.Message);
// Relancement de l'exception :

}
catch
{
// Traitement de toutes les autres exceptions
}
-Un bloc catch peut spécifier le type d’exception à
intercepter( FileNotFoundException,
IndexOutOfRangeException,
UnauthorizedAccessException ,,,)
-La spécification de type est appelée filtre
d’exception
-Le type d’exception doit être dérivé de Exception
Les classes en C#
•Les classes sont introduites avec « class »
•Les données membres se déclarent comme des
variables
•Les méthodes comme des fonctions inline
•Plusieurs types de mode d'accès :
–private (accessibles de la classe, par défaut),
–public (accessibles de tout le monde),
–protected (accessibles des classes dérivées),
–internal (accessibles depuis l'assemblée, cf. ci-
après)
Passage d'arguments
• Par valeurs
– Appel : int a = 3; f(a);
– Description : static void f(int i) {instructions;}
• Par référence
– Appel : int a = 3; f(ref a);
– Description : static void f(ref int i)
{instructions;}
• De tableau
– Appel : int[] ta = {1,2,3}; f(ta);
– Description : static void f(int [] ti) {instructions;}
Méthodes et paramètres
•Les méthodes peuvent être surchargées
•Les paramètres sont en entrée seule par défaut :
–pour un passage par référence, utiliser « ref »,
–pour un paramètre en sortie, utiliser « out »,
–pour la valeur de retour, utiliser « return ».
•Le mode de passage des paramètres doit être
fourni à l'appel explicitement
•.NET accepte les paramètres par défaut depuis la
version 4.0
Les fonctions
-Pas de passage d'arguments par adresse
-Passage d'arguments par référence
seulement pour les tableaux et objets
-Passage d'arguments par valeur ou référence
pour les autres types
void signale une fonction qui ne retourne pas
de valeurs
Régions
Les parties du code peuvent être délimitées
dans des "régions" en les bornant par les
délimiteurs #region et #endregion
#region Test
int i = 1;
#endregion
Un bouton de réduction en forme de "-"
apparaît alors pour masquer cette partie du
code
Manipulation des objets avec
C#
utilisation des classes
Description d'une classe
Classe Personne avec deux attributs (Nom et
Prénom), un constructeur (Personne()) et une
méthode (Affiche()).
class Personne
{public string Nom;
public DateTime Naiss;
public Personne(string N, DateTime D) {Nom = N;Naiss=D;}
public void Affiche()
{MessageBox.Show(Nom);}}
Le destructeur est inutile en C #
S'il n'est pas décrit, un constructeur est implicite.
Utilisation d'un objet

// déclaration
Personne P1;
//instanciation
P1 = new Personne("Dupond",DateTime.Parse("01/01/60"));
P1.Affiche();
MessageBox.Show(P1.Naiss.ToString());

Remarque : DateTime est une classe. Des méthodes


de conversions en chaîne sont donc nécessaires.
Surcharges de méthodes
Des méthodes d'une même classe peuvent
porter le même nom mais doivent se distinguer
par leur type ou nombre d'arguments :
class Personne
{...
public void Modifier(String N) {Nom = N;}
public void Modifier(DateTime D) {Naiss = D;}
public void Modifier(String N, DateTime D)
{Nom = N;Naiss = D;}
}
Tableaux d'objets
Il est nécessaire d'appeler le constructeur pour
chaque cellule du tableau :

Personne[] TabPers; // déclaration


TabPers = new Personne[10];//allocation
for(int i=0;i<TabPers.Length;i++) // pour chaque élément
TabPers[i]=new Personne("", DateTime.Parse("01/01/1900"));
// appel du constructeur
Attributs et méthodes statiques
Les attributs ou les méthodes statiques peuvent
être appelé indépendamment de toute instance.
class Personne
{public static string Prénom = "A Définir";
...
public static void Test() {MessageBox.Show("Test");}

Personne.Test();
MessageBox.Show(Personne.Prénom);
Remarque : Show de MessageBox et Parse de DateTime sont
des méthodes statiques
Polymorphisme
Des attributs ou des méthodes de classes différentes
peuvent porter le même nom. La forme adoptée par
l'attribut ou la méthode dépend alors de l'objet sur lequel
il ou elle porte.
class Acte
{public string Code;
public void Affiche() {MessageBox.Show(Code);}}
….
P1 = new Personne("Dupond",DateTime.Parse("01/01/60"));
P1.Affiche();
A1 = new Acte();
A1.Affiche();
Composition
Une classe peut contenir un autre classe
class Personne
{public Personne(string N, DateTime D) {Nom = N;Naiss=D; A = new
Adresse();}
public class Adresse { string rue;
public string ville ;
public string GetRue() {return rue;}}
public void Vi(string v){A.ville = v;}
public Adresse A;
...}

P1.Vi("Paris");
MessageBox.Show (P1.A.ville);
Héritage
A partir d’une classe mère, on peut créer une
classe fille enrichie de méthodes et d ’attributs.
class Patient: Personne
{public string Nip;
public Patient (string N, DateTime D, string I) : base(N,D) {Nip =
I;}
public new void Affiche() {MessageBox.Show(Nip);}}

Patient Pat;
Pat = new Patient("Dupond",DateTime.Parse("01/01/60"),"0303");
Pat.Affiche();
Lire et écrire dans un fichier en C#
La classe File fournit des fonctionnalités de gestion
de fichiers en C#.
La méthode File.WriteAllText(path) peut être utilisée
pour écrire une chaîne dans un fichier dans le
chemin path.
L’exemple de code suivant nous montre comment
écrire des données dans un fichier avec la fonction
File.WriteAllText() en C#.
using System;
using System.IO;

namespace write_to_a_file
{
class Program
{
static void Main(string[] args)
{
string path = "C:\\File\\file.txt";
string Text = "Hello, Hi, ByeBye";
File.WriteAllText(path, Text);
}
}
}
Ecrire des données dans un fichier
avec la classe StreamWriter
La classe StreamWriter est utilisée pour écrire des
données dans un flux dans un encodage
particulier en C#.
La méthode StreamWrite.WriteLine() permet
d’écrire une variable chaîne dans un fichier.
L’exemple de code suivant nous montre comment
écrire des données dans un fichier avec la
méthode StreamWriter.WriteLine() en C#.
using System;
using System.IO;

namespace write_to_a_file
{
class Program
{
static void Main(string[] args)
{
string path = "C:\\File\\file.txt";
string Text = "Hello and Welcome";
using (StreamWriter writetext = new StreamWriter(path))
{
writetext.WriteLine(Text);
}
}
}
}
Lire les données d’un fichier avec la
classe StreamReader
La classe StreamReader permet de lire les
données d’un flux dans un encodage particulier
en C#.
La méthode StreamReader.ReadLine() peut être
utilisée pour lire des données de chaîne à partir
d’un fichier.
L’exemple de code suivant nous montre comment
lire les données d’un fichier avec la méthode
StreamReader.ReadLine() en C#.
using System;
using System.IO;

namespace write_to_a_file
{
class Program
{
static void Main(string[] args)
{
string path = "C:\\File\\file.txt";
using (StreamReader readtext = new StreamReader(path))
{
string readText = readtext.ReadLine();
Console.WriteLine(readText);
}
}
}
}
Fonctions virtuelles
Tout objet de la classe Patient est un objet de la classe Personne.
Ainsi, la syntaxe suivante est acceptée :
Personne Pat1;
Pat1 = new Patient("Dupond",DateTime.Parse("01/01/60"),"0303");

Pour savoir quelle méthode appelée, C # se base sur la définition


stricte de Pat1.
Ainsi Pat1 est un objet Patient, mais Pat1.Affiche() , fait appèle à
Affiche() de Personne !
Pour remédier à ce problème, il faut qualifier :
dans Personne : public virtual void Affiche();
dans Patient : public override void Affiche();
Classes abstraites
Une classe abstraite contient la définition d'une
fonction (prototype) sans son implémentation qui
sera réalisée dans une classe dérivée.
Elle ne peut pas être instanciée.
abstract class ProtoSéjour
{string No_Séjour ;
public ProtoSéjour( string Num) {No_Séjour=Num;}
public abstract void Test();}
class Séjour : ProtoSéjour
{public Séjour( string N) : base(N) {}
public override void Test(){MessageBox.Show("OK");}}
Interfaces
On peut définir uniquement les méthodes à
implémenter dans la classe
interface ObjetMétier
{void Test ();
void Affiche(string S); }
interface Serveur
{void GetVersion();}
class IDT : ObjetMétier, Serveur
{public void Test (){MessageBox.Show("OK");}
public void Affiche(string S) {MessageBox.Show(S);}
public void GetVersion() {MessageBox.Show("Version :");} }
C# MySQL

60
XAMPP

61
62
Télécharger Connector/Net

• Premièrement soyez sure d’avoir télécharger et installer


MySQL Connector-NET pour MySQL

• http://dev.mysql.com/downloads/connector/net/6.1.html

63
Création de la base de données

•create database ConnectCsharpToMysql;

•use ConnectCsharpToMysql;

64
Création de la Table

• Create table: tableinfo

create table tableInfo (


id INT NOT NULL AUTO_INCREMENT,
name VARCHAR(30),
age INT, PRIMARY KEY(id) );
65
//Connexion à la base de données
Les déclarations et initialisations des variables utiliseront:
• connection: sera utiliser pour ouvrir la connexion à la base de données.
• server: indiquera où est hébérgé votre serveur
• database: est le nom de la base de données que nous utiliserons
• uid: nom d’utilisateur de notre MySQL.
• password: mot de passe de MySQL.
• connectionString: contient le chaîne pour connecter à la base de données, et sera assigné à la variable de
connexion.

66
Installez le package MySql.Data
Vous pouvez utiliser le gestionnaire de packages pour l'ajouter en tant que
package et c'est le moyen le plus simple. Vous n'avez besoin de rien d'autre
pour travailler avec une base de données MySQL. Ou vous pouvez exécuter
cette commande dans la console du gestionnaire de packages :
PM> Install-Package MySql.Data

67
using MySql.Data;
using MySql.Data.MySqlClient;
namespace Data
{
public class DBConnection
{
private DBConnection()
{
}
public string Server { get; set; }
public string DatabaseName { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
private MySqlConnection Connection { get; set;}
private static DBConnection _instance = null;
public static DBConnection Instance()
{
if (_instance == null)
_instance = new DBConnection();
return _instance;
}
public bool IsConnect()
{
if (Connection == null)
{
if (String.IsNullOrEmpty(databaseName))
return false;
string connstring =
string.Format("Server={0}; database={1}; UID={2};
password={3}", Server, DatabaseName, UserName, Password);
Connection = new
MySqlConnection(connstring);
Connection.Open();
}

return true;
}

public void Close()


{
Connection.Close();
}
}
}
Exemple :
var dbCon = DBConnection.Instance();
dbCon.Server = "YourServer";
dbCon.DatabaseName = "YourDatabase";
dbCon.UserName = "YourUsername";
dbCon.Password = "YourPassword";
if (dbCon.IsConnect())
{
//suppose col0 and col1 are defined as VARCHAR in the
DB
string query = "SELECT col0,col1 FROM YourTable";
var cmd = new MySqlCommand(query, dbCon.Connection);
var reader = cmd.ExecuteReader();
while(reader.Read())
{
string someStringFromColumnZero =
reader.GetString(0);
string someStringFromColumnOne =
reader.GetString(1);
Console.WriteLine(someStringFromColumnZero + "," +
someStringFromColumnOne);
}
dbCon.Close();
}
Travailler avec Insert, Update, Select, Delete

Habituellement, Insérer, mettre à jour et supprimer sont utilisés pour écrire ou modifier des données dans la
base de données, tandis que Sélectionner est utilisé pour lire des données.
Pour cette raison, nous avons différents types de méthodes pour exécuter ces requêtes.
Les méthodes sont les suivantes :
ExecuteNonQuery : utilisé pour exécuter une commande qui ne renverra aucune donnée, par exemple
Insérer, mettre à jour ou supprimer.
ExecuteReader : utilisé pour exécuter une commande qui renverra 0 ou plusieurs enregistrements, par
exemple Select.
ExecuteScalar : utilisé pour exécuter une commande qui ne renverra qu'une seule valeur, par exemple,
Select Count(*).

71
Etapes
Commencez par Insérer, mettre à jour et supprimer, qui sont les plus simples. Le processus pour exécuter
avec succès une commande est le suivant :
1- Ouvrir la connexion à la base de données.
2- Créez une commande MySQL.
3- Affectez une connexion et une requête à la commande. Cela peut être fait à l'aide du constructeur ou à
l'aide des méthodes Connection et CommandText dans la classe MySqlCommand.
4- Exécutez la commande.
5- Fermez la connexion.

72
private void button1_Click(object sender, EventArgs e)
{
string query = "INSERT INTO tableinfo (name, age) VALUES('John Smith', '33')";
//open connection
if (this.OpenConnection() == true)
{
//create command and assign the query and connection from the constructor
MySqlCommand cmd = new MySqlCommand(query, connection);
//Execute command
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
}
73
private void button2_Click(object sender, EventArgs e)
{
string query = "UPDATE tableinfo SET name='Joe', age='22' WHERE name='John Smith'";
//Open connection
if (this.OpenConnection() == true)
{
//create mysql command
MySqlCommand cmd = new MySqlCommand();
//Assign the query using CommandText
cmd.CommandText = query;
//Assign the connection using Connection
cmd.Connection = connection;
//Execute query
cmd.ExecuteNonQuery();
//close connection
this.CloseConnection();
}
74
}
private void button3_Click(object sender, EventArgs e)
{
string query = "DELETE FROM tableinfo WHERE name='John Smith'";

if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
cmd.ExecuteNonQuery();
this.CloseConnection();
}
}

75
Étapes pour select
Pour exécuter une instruction Select, nous ajoutons quelques étapes supplémentaires et nous utilisons la
méthode ExecuteReader qui renverra un objet dataReader pour lire et stocker les données ou les
enregistrements.
1- Ouvrir la connexion à la base de données.
2- Créez une commande MySQL.
3- Affectez une connexion et une requête à la commande. Cela peut être fait à l'aide du constructeur ou à
l'aide des méthodes Connection et CommandText dans la classe MySqlCommand.
4- Créez un objet MySqlDataReader pour lire les enregistrements/données sélectionnés.
5- Exécutez la commande.
6- Lisez les enregistrements et affichez-les ou stockez-les dans une liste.
7- Fermez le lecteur de données.
8- Fermez la connexion.

76
private void button4_Click(object sender, EventArgs e)
{
string query = "SELECT * FROM tableinfo";
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand cmd = new MySqlCommand(query,
connection);
//Create a data reader and Execute the command
MySqlDataReader dataReader = cmd.ExecuteReader();
//Read the data and store them in the list
while (dataReader.Read())
{
textbox1.text += dataReader["id"] +"" +dataReader["name"] +
""+dataReader["age"] + "\r\n";
}
//close Data Reader
dataReader.Close();
//close Connection
this.CloseConnection();
77
}
}
Extra
Parfois, une commande ne renverra toujours qu'une seule valeur, comme par exemple si nous voulons
compter le nombre d'enregistrements, nous avons utilisé Select Count(*) from tableinfo ; dans ce cas,
nous devrons utiliser la méthodeExecuteScalar qui renvoie une valeur.
Le processus pour exécuter avec succès et ExecuteScalar est le suivant :
1- Ouvrir la connexion à la base de données.
2- Créez une commande MySQL.
3- Affectez une connexion et une requête à la commande. Cela peut être fait à l'aide du constructeur ou à
l'aide des méthodes Connection et CommandText dans la classe MySqlCommand.
4- Exécutez la commande.
5- Analysez le résultat si nécessaire.
6- Fermez la connexion.

78
private void button5_Click(object sender, EventArgs e)
{
string query = "SELECT Count(*) FROM tableinfo";
int Count = -1;
//Open Connection
if (this.OpenConnection() == true)
{ //Create Mysql Command
MySqlCommand cmd = new MySqlCommand(query, connection);
//ExecuteScalar will return one value
Count = int.Parse(cmd.ExecuteScalar() + "");
//close Connection
this.CloseConnection();
MessageBox.Show(Count.ToString());
}
}

79
Programmation évènementielle avec les WinForms
Les évènements
La programmation évènementielle est fondée sur les évènements. Un
évènement représente un message envoyé à l'application. Les évènements
peuvent être d'origines diverses : action de l'utilisateur (déplacement de la
souris, clic sur un bouton, appui sur une touche du clavier, etc.) ou
évènement système (chargement d'un fichier, déclenchement d'une
minuterie, etc.).

Le plus souvent, un évènement contient des informations qui dépendent


du type d'évènement. Ces données peuvent être utilisées par
l'application pour réagir au mieux. Elle choisit les évènements auxquels
elle va répondre par un traitement particulier, et ignore tous les autres.
Structure d'une application WinForms
Une application WinForms est structurée autour d'un ou plusieurs
formulaires, appelés forms.

Lorsqu'on crée une nouvelle application WinForms, l'IDE Visual Studio


génère automatiquement plusieurs éléments qu'il est important d'identifier.

Les fichiers du répertoire Properties sont gérés par Visual Studio. Ils ne


doivent pas être édités manuellement. Étudions en détail le reste de
l'arborescence.
Programme principal
Le fichier Program.cs correspond au point d'entrée dans l'application.
Voici son contenu par défaut.

static void Main()


{
Application.EnableVisualStyles();

Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}

Comme pour une application console, la méthode statique Main est le


point d'entrée dans le programme. Cette méthode crée (new Form1()) puis
affiche le premier formulaire de l'application.
Anatomie d'un formulaire
Chaque formulaire WinForms est décrit par deux fichiers :

un fichier .Designer.cs qui contient le code généré automatiquement par l'IDE


lors de la conception graphique du formulaire ;

un fichier .cs qui contient le code C# écrit par le développeur pour faire réagir


le formulaire aux évènements qui se produisent. Ce fichier est appelé code
behind.

Après chaque création de formulaire, une bonne pratique consiste à lui


donner immédiatement un nom plus parlant, par exemple MainForm pour le
formulaire principal. Pour cela, faites un clic droit sur le formulaire dans
l'arborescence, puis choisissez Renommer.

Le fichier « code behind » .cs associé à un formulaire est accessible en


faisant un clic droit sur le formulaire puis en choisissant Afficher le code, ou à
l'aide du raccourci clavier F7. Voici son contenu initial.
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
}

Il s'agit de la définition d'une classe avec son constructeur.

Cette classe hérite de la classe Form, définie par le framework .NET et qui


rassemble les fonctionnalités communes à tous les formulaires.

On remarque la présence du mot-clé partial. Il indique que seule une partie


du code de la classe est présente dans ce fichier.

e reste se trouve, comme vous l'avez deviné, dans le fichier .Designer.cs.


Édition graphique d'un formulaire
Un double-clic sur le formulaire dans l'arborescence déclenche l'apparition
du concepteur de formulaire. Cette interface va permettre d'éditer l'apparence
du formulaire. Nous en reparlerons plus loin.
Ajout d'un contrôle
L'édition du formulaire se fait en y glissant/déposant des contrôles, rassemblés
dans une boîte à outils (liste de gauche). De nombreux contrôles sont
disponibles pour répondre à des besoins variés et construire des IHM riches et
fonctionnelles. Parmi les plus utilisés, on peut citer : 

Label qui affiche un simple texte ; 

TextBox qui crée une zone de saisie de texte ; 

Button qui affiche un bouton ; 

ListBox qui regroupe une liste de valeurs ; 

CheckBox qui affiche une case à cocher ; 

RadioButton qui affiche un radio bouton.

Pour découvrir le comportement d'un contrôle, testez-le !

Par exemple, l'ajout d'un bouton au formulaire se fait en cliquant sur le contrôle
« Button » dans la boîte à outils, puis en faisant glisser le contrôle vers le
formulaire.
Propriétés d'un contrôle
La sélection d'un contrôle (ou du formulaire lui-même) dans le concepteur
permet d'afficher ses propriétés dans une zone dédiée, située par défaut en
bas à droite de l'IDE.
Chaque contrôle dispose d'un grand nombre de propriétés qui gouvernent
son apparence et son comportement. Parmi les propriétés essentielles,
citons : 

(Name) : le nom de l'attribut représentant le contrôle dans la classe ; 

Dock et Anchor : l'ancrage du contrôle dans celui qui le contient, c'est-à-dire


sa position ; 

Enabled : indique si le contrôle est actif ou non ; 

Text : le texte affiché par le contrôle ; 

Visible : indique si le contrôle est visible ou non.


Par exemple, donnons à notre nouveau bouton le nom helloBtn et le
texte Cliquez-moi !. Donnons également à notre formulaire le
titre Bienvenue (propriété Text du formulaire).
Gestion des évènements
Ajout d'un gestionnaire d'évènements
En double-cliquant sur un contrôle dans le concepteur de formulaire, on
ajoute un gestionnaire d'évènements pour l'évènement par défaut associé
au contrôle. Dans le cas d'un bouton, l'évènement par défaut est le clic.

Un gestionnaire d'évènements représente le code exécuté lorsque


l'évènement associé se produit. Tous les gestionnaires sont regroupés
dans le fichier « code behind » .cs. Voici le gestionnaire par défaut associé
à un clic sur un bouton.

public partial class MainForm : Form


{
// ...
// Gère le clic sur le bouton helloBtn
private void helloBtn_Click(object sender, EventArgs e)
{
}
}
Un gestionnaire d'évènements WinForms correspond à une méthode dans la
classe associée au formulaire. Le nom de cette méthode est composé du nom
du contrôle suivi de celui de l'évènement. Cette méthode reçoit deux
paramètres offrant des détails sur l'évènement : 

.sender représente le contrôle qui a déclenché l'évènement ; 

.e rassemble les paramètres liés à l'évènement. Son contenu dépend du type


de l'évènement.

Affichage d'un message


Modifions le gestionnaire pour afficher un message à l'utilisateur.
private void helloBtn_Click(object sender, EventArgs e)
{
MessageBox.Show("Merci !", "Message",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}

La méthode statique Show de la classe MessageBox affiche un message à


l'utilisateur. Plusieurs surcharges de cette méthode permettent de paramétrer
l'apparence du message (texte, titre, boutons, icône).
Voici le résultat d'un clic sur le bouton du formulaire, une fois l'application
exécutée.
Dans le concepteur de formulaire, la zone des propriétés permet de gérer les
évènements associés à un contrôle (ou au formulaire lui-même). Un clic sur le
petit bouton en forme d'éclair affiche la liste de tous les évènements que
l'élément peut générer, ainsi que les gestionnaires d'évènements ajoutés.
Le lien entre le contrôle et le gestionnaire se fait dans le fichier .Designer.cs.
Son contenu est complexe et géré par Visual Studio, mais on peut tout de
même le consulter pour y trouver le code ci-dessous.
partial class MainForm
{
// ...
#region Code généré par le Concepteur Windows Form
/// <summary>
/// Méthode requise pour la prise en charge du
concepteur - ne modifiez pas
/// le contenu de cette méthode avec l'éditeur de
code.
/// </summary>
private void InitializeComponent()
{
this.helloBtn = new
System.Windows.Forms.Button();
// ...
this.helloBtn.Click += new
System.EventHandler(this.helloBtn_Click);
// ...
}
#endregion
private System.Windows.Forms.Button helloBtn;
}
L'attribut privé helloBtn correspond au bouton ajouté au formulaire. Il est
instancié dans la méthode InitializeComponent, appelée par le constructeur du
formulaire (voir plus haut). Ensuite, on lui ajoute (opérateur +=) le
gestionnaire helloBtn_Click pour l'évènement Click.

Principaux contrôles WinForms


Nommage des contrôles
Comme indiqué précédemment, il est fortement recommandé de donner un
nom parlant à un contrôle immédiatement après son ajout au formulaire. Cela
augmente fortement la lisibilité du code utilisant ce contrôle.

On peut aller plus loin et choisir une convention de nommage qui permet
d'identifier clairement le type du contrôle. Il n'existe pas de consensus à ce
sujet :

-on peut rester générique et suffixer tous les contrôles par Ctrl ;

-on peut choisir un suffixe différent pour chaque type de contrôle.

L'important est de rester cohérent dans la convention choisie afin que le code
soit uniforme.
Affichage de texte
Le contrôle Label est dédié à l'affichage d'un texte non modifiable.

Il dispose d'une propriété Text qui permet de récupérer ou de définir le texte


affiché par le contrôle.
Saisie de texte
Le contrôle TextBox crée une zone de saisie de texte.

Voici ses propriétés importantes : 

Text permet de récupérer ou de définir la valeur saisie ; 

Multiline précise si le texte saisi peut comporter une ou plusieurs lignes ; 

ReadOnly permet, quand elle vaut true, d'en faire une zone en lecture seule (saisie
impossible).

L'évènement TextChanged permet d'être notifié lors de la modification du texte de la


zone de saisie.
Liste déroulante
Le contrôle ComboBox définit une liste déroulante.

Voici ses propriétés importantes : 

-Items regroupe ses valeurs sous la forme d'une liste (collection) d'objets. On


peut ajouter des valeurs dans la liste déroulante dans le concepteur du
formulaire ou via le code ; 

-DropDownStyle permet de choisir le style de la liste. Pour obtenir des valeurs


non éditables par l'utilisateur, il faut choisir le style DropDownList ; 

-SelectedIndex récupère ou définit l'indice de l'élément actuellement


sélectionné. Le premier élément correspond à l'indice 0 ; 

-SelectedItem renvoie l'élément actuellement sélectionné sous la forme d'un


objet.
// Ajoute 3 pays à la liste
countryCB.Items.Add("France");
countryCB.Items.Add("Belgique");
countryCB.Items.Add("Suisse");
// Sélectionne le 2e élément de la liste
countryCB.SelectedIndex = 1;

L'évènement SelectedIndexChanged permet de gérer le changement de la


valeur sélectionnée de la liste.

// Gère le changement de sélection dans la liste


déroulante
private void countryCB_SelectedIndexChanged(object
sender, EventArgs e)
{
// On caste l'objet renvoyé par SelectedItem vers
le type chaîne
string selectedValue = (string)
countryCB.SelectedItem;
// ...
}
Liste d'éléments
Le contrôle ListBox permet de créer une liste d'éléments.

Voici ses propriétés importantes : 

-Items regroupe ses valeurs sous la forme d'une liste (collection) d'objets. On


peut ajouter des valeurs dans la liste déroulante dans le concepteur du
formulaire ou via le code ; 

-SelectionMode permet de choisir si la liste est à sélection simple, multiple ou


si la sélection est désactivée ; 

-SelectedIndex récupère ou définit l'indice de l'élément actuellement


sélectionné. Le premier élément correspond à l'indice 0 ; 

-SelectedItems renvoie les éléments actuellement sélectionnés sous la forme


d'une liste d'objets.
// Ajoute 4 éléments à la liste
hardwareLB.Items.Add("PC");
hardwareLB.Items.Add("Mac");
hardwareLB.Items.Add("Tablette");
hardwareLB.Items.Add("Smartphone");
// Sélectionner le 1er élément
hardwareLB.SelectedIndex = 0;

L'évènement SelectedIndexChanged permet de gérer le changement de


sélection dans la liste.
// Gère le changement de sélection dans la liste
private void hardwareLB_SelectedIndexChanged(object
sender, EventArgs e)
{
// Parcours de la liste des éléments sélectionnés
foreach (string value in hardwareLB.SelectedItems)
{
// ...
}
}
Bouton
Le contrôle Button permet de créer un bouton.

Voici ses propriétés importantes : 

-Text récupère ou définit le texte affiché dans le bouton ; 

-Enabled active ou désactive le bouton (clic impossible) ; 

-DialogResult définit le résultat renvoyé lors d'un clic sur le bouton


quand le formulaire est affiché de manière modale (voir chapitre
suivant).

L'évènement Click permet de gérer le clic sur le bouton.


// Gère le clic sur le bouton de connexion
private void connectBtn_Click(object sender, EventArgs e)
{
// ...
}
Case à cocher
Le contrôle CheckBox permet de créer une case à cocher

Voici ses propriétés importantes : 

-Checked récupère ou définit l'état de la case (cochée ou non) ; 

-Text représente le label associé à la case à cocher.

L'évènement CheckedChanged permet de gérer le changement d'état de la


case à cocher.
// Gère le clic sur le bouton de connexion
private void connectCbx_Checked(object sender, EventArgs
e)
{
// ...
}
Radio bouton
Le contrôle RadioButton permet de créer un bouton radio. Similaire à la case à
cocher, il se différencie de ce dernier par le fait qu'au plus un seul radio bouton
d'un ensemble peut être coché à un instant donné.

Voici ses propriétés importantes : 

-Checked récupère ou définit l'état de la case (cochée ou non) ; 

-Text représente le label associé au radio bouton.


Sélectionner un radio bouton va automatiquement décocher le précédent radio
bouton sélectionné. Les radio boutons sont liés entre eux par leur conteneur.
Ainsi, tous les radios bouton d'un conteneur forme un ensemble dans lequel un
seul bouton peut être coché.L'évènement CheckedChanged permet de gérer le
changement d'état du radio bouton.

// Gère la sélection du choix « oui »


private void ouiRad_Checked(object sender,
EventArgs e)
{
// ...
}
Barre de menus
Le contrôle MenuStrip permet de créer une barre de menus déroulants. Une
entrée de menu déroulant peut être une commande (MenuItem), une liste
déroulante, une zone de texte ou un séparateur.
L'évènement Click permet de gérer le clic sur une commande du menu
déroulant.
// Gère le clic sur la commande Quitter
private void quitterToolStripMenuItem_Click(object
sender, EventArgs e)
{
// ...
}
Les nouveautés de C# 9
Target-typed new

En C# 9, il sera possible d'omettre le type dans une expression de création


d'objet, à condition que le type puisse être inféré d'après le contexte. Cela rend
le code plus concis et moins répétitif. Par exemple :

private Dictionary<string, object> _properties = new();


Vérification de nullité des paramètres

Cette feature introduit une syntaxe très simple pour vérifier automatiquement
si un paramètre d'une méthode est null. Par exemple, le code suivant:

public string SayHello(string name)

{    

if (name == null)        

throw new ArgumentNullException(nameof(name));    

return $"Hello {name}";

}
Pourra être simplifié en ceci :
public string SayHello(string name!) => $"Hello {name}";
Le point d'exclamation après le nom du paramètre ajoute automatiquement
le null-check pour ce paramètre.

Améliorations du pattern matching

C# 9 apporte quelques améliorations bienvenues au pattern matching. La


plus utile à mon avis est le pattern not, qui permet d'écrire ce genre de
choses :

if (foo is not null) { ... }

if (animal is not Dog) { ... }


Les opérateurs relationnels (<, >=, etc.) et logiques (and et or) peuvent aussi
être utilisés dans le pattern matching :

return size switch

{   

 < 10 => "small",

  >= 10 and < 100 => "medium",

   _ => "large"

Les types record et les expressions with

C'est à mon avis la plus importante feature de C# 9. Créer un simple type de


données en C# a toujours été plus laborieux que cela ne devrait ; il faut créer
une classe, déclarer des propriétés, ajouter un constructeur si on veut que le
type soit immuable, redéfinir Equals et GetHashCode, éventuellement ajouter
un déconstructeur, etc. Au final, ça fait pas mal de code de plomberie pour
obtenir des fonctionnalités assez basiques. Par exemple, une simple classe
représentant un point pourrait actuellement ressembler plus ou moins à ça :
public class Point : Iequatable<Point>

{   

 public Point(int x, int y) =>

         (X, Y) = (x, y); 

  public int X { get; }

      public int Y { get; }

      public bool Equals(Point p) =>

         (p.X, p.Y) == (X, Y)

      public override bool Equals(object other) =>

         other is Point p && Equals(p);     

public override int GetHashCode() =>        

(X, Y).GetHashCode();    

 public void Deconstruct(out int x, out int y) =>        

(x, y) = (X, Y);

}
Les types record en C# 9 vont rendre tout ça beaucoup plus simple ! En
utilisant un type record, le code ci-dessus peut être résumé à ceci :

public data class Point(int X, int Y);

Eh oui, une seule ligne, et même pas bien longue ! Et cela inclut toutes les
fonctionnalités du code précédent. Sympa, non ? Il est également possible de
faire la même chose avec une structure plutôt qu'une classe, si un type valeur
est plus approprié.

Une chose à noter : les types record sont immuables, on ne peut pas modifier
les valeurs de leurs propriétés. Donc si on veut modifier une instance d'un type
record, il faut en fait en créer une nouvelle (c'est le même principe qu'avec les
dates ou les strings, par exemple). L'approche "classique" pour faire ça
ressemblerait à ceci :

Point p1 = new Point(1, 2);

Point p2 = new Point(p1.X, 3);


Grosso modo, on copie toutes les propriétés de l'objet d'origine, sauf celles
qu'on veut modifier. Dans cet exemple, ce n'est pas un problème car il n'y a que
deux propriétés, mais s'il y en avait plus ça deviendrait vite laborieux.

C# 9 introduit les expressions with, qui permettent de faire ceci :

Point p1 = new Point(1, 2);

Point p2 = p1 with { Y = 3 };

Une expression with crée un clone de l'objet d'origine, en remplaçant les


valeurs des propriétés spécifiées entres les accolades.
Target-typed conditionals

Il y a une petite chose qui agace les développeurs C# depuis bien longtemps :
quand on utilise l'opérateur conditionnel (aussi appelé opérateur ternaire), les
deux "branches" doivent avoir le même type, ou du moins il doit exister une
conversion de l'une vers l'autre. Si bien que le code suivant ne compile pas :

Stream s = inMemory ? new MemoryStream() : new FileStream(path);

En effet, il n'existe pas de conversion entre MemoryStream et FileStream, et le


compilateur ne sait donc pas déterminer le type de l'expression dans son
ensemble. Pour corriger ça, il faut explicitement convertir une branche ou
l'autre en Stream.

En C# 9, le code ci-dessus sera enfin valide ! Il faut juste que les deux
branches soient convertibles vers le type de destination.
Covariance du type de retour

Actuellement, quand on redéfinit une méthode virtuelle d'une classe de base,


la méthode redéfinie doit avoir le même type de retour que celle de la classe
de base. Dans certaines situations, il serait plus pratique de pouvoir renvoyer
un type plus spécifique. C# 9 rend cela possible, en permettant à la méthode
redéfinie de renvoyer un type dérivé du type de retour de la méthode de base :

public class Thing

{    

public virtual Thing Clone() => new Thing();

public class MoreSpecificThing : Thing

{    

// Override with a more specific return type    

public override MoreSpecificThing Clone() => new MoreSpecificThing();

}
Instructions de niveau racine

Cette feature vise à réduire le code "boilerplate" pour les programmes simples.
Actuellement, même le programme le plus simple a besoin d'une classe avec
une méthode Main :

using System; 

public class Program

{    

public static void Main()    

{        

Console.WriteLine("Hello world");    

Tout ce code n'apporte pas grand chose d'utile, et complique l'apprentissage


pour les débutants, car il oblige à appréhender tout de suite la notion de classe
et de méthode.
En C# 9, il sera possible d'omettre la classe Program et la méthode Main, ce qui
permettra de simplifier le code précédent comme ceci :

using System;

Console.WriteLine("Hello world");

Vous aimerez peut-être aussi