Exercice — Générateur de mot de passe (app fenêtrée)

Premier vrai projet Windows : tu vas construire une fenêtre avec des boutons, des cases à cocher, un champ de texte, et y connecter du code C# pour générer un mot de passe selon les choix de l'utilisateur. L'objectif n'est pas seulement de produire l'app — c'est de comprendre comment une interface graphique et du code se parlent.

    5ttr 6ttr
  • Exercice ambitieux

C'est un projet ambitieux : tu vas écrire ta première application Windows native, avec une vraie fenêtre, des contrôles cliquables et du code qui réagit à l'utilisateur. Ne te laisse pas impressionner par la longueur de l'énoncé — chaque étape est petite et l'ordre est pensé pour que rien ne te bloque.

L'application à construire s'appelle Générateur de mot de passe. L'utilisateur choisit la longueur souhaitée, coche les types de caractères qu'il veut inclure (minuscules, majuscules, chiffres, caractères spéciaux), clique sur un bouton, et un mot de passe aléatoire s'affiche.


🎯 Objectifs d'apprentissage

À la fin de ce projet, tu seras capable de :

  1. Créer une application Windows Forms dans JetBrains Rider
  2. Construire une interface en plaçant des composants graphiques (Label, Button, CheckBox, etc.)
  3. Renommer correctement tes composants et comprendre pourquoi c'est essentiel
  4. Connecter un événement (clic sur un bouton) à une méthode de ton code
  5. Lire les valeurs saisies par l'utilisateur et les utiliser dans une logique
  6. Utiliser la classe Random pour générer un résultat aléatoire
  7. Construire dynamiquement une chaîne de caractères
  8. Gérer les cas d'erreur de base et afficher un message clair

🖼️ Aperçu de l'interface

Voici à quoi ressemblera ton application une fois terminée : Capture d'écran illustrative

Six éléments à placer : un titre, un champ pour la longueur, quatre cases à cocher, un bouton Générer, une zone de texte pour le résultat, et un message d'information.


🧠 Avant de commencer : ce que tu dois savoir

Windows Forms, c'est quoi ?

Windows Forms (souvent abrégé WinForms) est la technologie historique de Microsoft pour créer des applications fenêtrées Windows. Elle existe depuis 2002. C'est la plus simple à prendre en main parce qu'elle permet de dessiner ton interface à la souris dans un éditeur visuel — pas besoin d'écrire du XML ni du code pour positionner les contrôles.

Une application WinForms est composée de :

  • Une ou plusieurs Form — chaque fenêtre est une classe Form
  • Des contrôles posés sur la fenêtre (Button, Label, TextBox…)
  • Du code C# qui réagit aux actions de l'utilisateur

Le modèle événementiel

C'est le concept central à comprendre. Contrairement à un programme console qui s'exécute ligne par ligne du début à la fin, une application fenêtrée :

  1. Affiche la fenêtre
  2. Attend que l'utilisateur fasse quelque chose (clic, frappe au clavier…)
  3. Quand quelque chose arrive, exécute la méthode liée à cette action
  4. Retourne attendre

On dit que l'application est pilotée par les événements (🇬🇧 event-driven). Cliquer sur le bouton Générer déclenchera l'événement Click, qui appellera la méthode que tu auras écrite.

💡 Cette façon de penser est très différente d'un programme console. Au début, l'idée de "code qui ne s'exécute qu'à la demande" peut surprendre. C'est exactement comme une application mobile : rien ne se passe tant que tu ne touches pas l'écran.


Étape 1 — Créer la solution dans Rider

Procédure

  1. Ouvre JetBrains Rider
  2. Clique sur New Solution
  3. Dans la liste de gauche, choisis : .NETDesktopWindows Forms App

Configuration

Remplis les champs comme ceci :

Champ Valeur
Solution name GenerateurMotDePasse
Project name GenerateurMotDePasseApp
Solution directory un dossier clair (par exemple D:\Projets\C#\)
Framework .NET 8.0 (ou la version utilisée en classe)

💡 Solution vs Projet : une solution est un conteneur qui peut regrouper plusieurs projets (par exemple : une UI + une bibliothèque + des tests). Ici, on n'a qu'un seul projet, mais Rider impose cette structure — c'est normal.

Vérification

Clique sur le bouton Run (▶ vert, en haut). Une fenêtre vide s'affiche. Ferme-la.

👉 Si tu vois cette fenêtre vide, tout fonctionne. Tu peux passer à l'étape suivante. Sinon, retourne aux étapes de configuration.


Étape 2 — Construire l'interface

Dans l'explorateur de fichiers de Rider, double-clique sur Form1.cs. Une vue spéciale s'ouvre : c'est le concepteur visuel (🇬🇧 designer) qui te permet de dessiner ta fenêtre.

La boîte à outils

À droite (ou via le menu View → Toolbox), tu trouves la boîte à outils (🇬🇧 Toolbox) avec tous les contrôles disponibles. Tu vas y piocher.

Placer les contrôles

Glisse-dépose les contrôles suivants sur ta Form1 :

Contrôle Rôle dans l'app
Label Le titre de la fenêtre
Label Texte « Longueur : »
NumericUpDown Le champ numérique pour la longueur
CheckBox × 4 Une case par type de caractère
Button Le bouton Générer
Label Texte « Mot de passe : »
TextBox La zone qui affichera le résultat
Label La ligne de message

Place-les en respectant grossièrement le mockup plus haut. La perfection visuelle peut attendre — on s'en occupe à la fin.

Renommer les contrôles : indispensable

Sélectionne chaque contrôle, puis dans le panneau Properties (à droite), trouve la propriété (Name) et change-la. Sans renommage clair, tu te perdras dans ton propre code dans 5 minutes.

Contrôle (Name) Autre propriété à régler
Label titre lblTitre Text = "GÉNÉRATEUR DE MOT DE PASSE"
NumericUpDown numLongueur Minimum = 4, Maximum = 64, Value = 12
CheckBox 1 chkMinuscules Text = "Lettres minuscules", Checked = true
CheckBox 2 chkMajuscules Text = "Lettres majuscules", Checked = true
CheckBox 3 chkChiffres Text = "Chiffres", Checked = true
CheckBox 4 chkSpeciaux Text = "Caractères spéciaux"
Button btnGenerer Text = "Générer"
TextBox txtResultat ReadOnly = true, Font plus grosse
Label message lblMessage Text = "" (vide au départ)

Les conventions de nommage

Tu as remarqué les préfixes : lbl pour Label, txt pour TextBox, btn pour Button, chk pour CheckBox, num pour NumericUpDown. Ce n'est pas obligatoire pour le compilateur — c'est une convention qui te permet de voir immédiatement de quel type est un contrôle juste en lisant son nom dans le code.

💡 Sans convention, tu te retrouves avec des password1, password2, password3 et tu ne sais plus lequel est le champ texte, lequel est le label, lequel est la case. Avec convention : txtPassword, lblPassword, chkPassword — zéro ambiguïté.


Étape 3 — Connecter le bouton à du code (test)

Avant d'écrire la vraie logique, on fait un test minimal pour s'assurer que le bouton réagit.

Double-clique sur le bouton btnGenerer dans le concepteur. Rider :

  1. Crée automatiquement une méthode appelée btnGenerer_Click dans Form1.cs
  2. Lie cette méthode à l'événement Click du bouton
  3. T'ouvre le code à cet endroit précis

Tu vois quelque chose comme :

private void btnGenerer_Click(object sender, EventArgs e)
{

}

Tape dedans :

private void btnGenerer_Click(object sender, EventArgs e)
{
    MessageBox.Show("Bouton cliqué !");
}

Lance l'application (▶). Clique sur Générer. Une boîte de dialogue doit apparaître.

💡 Pourquoi ce test ? Parce qu'il isole une seule responsabilité : le bouton réagit-il ? Si oui, on sait que tout le câblage interface↔code fonctionne. Si plus tard ta vraie logique ne marche pas, tu sauras que le problème est dans la logique, pas dans la connexion. C'est une habitude à prendre dans tous tes projets : avancer par petits pas validés.


Étape 4 — Lire les valeurs saisies par l'utilisateur

Remplace le MessageBox.Show par le code suivant :

private void btnGenerer_Click(object sender, EventArgs e)
{
    int longueur = (int)numLongueur.Value;

    bool inclureMinuscules = chkMinuscules.Checked;
    bool inclureMajuscules = chkMajuscules.Checked;
    bool inclureChiffres   = chkChiffres.Checked;
    bool inclureSpeciaux   = chkSpeciaux.Checked;
}

Décortiquons

  • numLongueur.Value retourne un decimal (pour pouvoir gérer aussi des valeurs à virgule). On le convertit explicitement en int avec (int)… — c'est un cast.
  • chkMinuscules.Checked est un bool qui vaut true si la case est cochée, false sinon. Pas besoin de conversion.

💡 Conseil de méthode : à ce stade, tu peux temporairement ajouter MessageBox.Show($"Longueur : {longueur}"); à la fin de la méthode pour vérifier que la valeur est bien lue. C'est une forme rudimentaire de débogage. Tu retireras la ligne avant de continuer.


Étape 5 — Construire l'alphabet de caractères autorisés

L'idée : selon les cases cochées, on assemble une chaîne qui contiendra tous les caractères qu'on autorise à tirer au sort.

string caracteres = "";

if (inclureMinuscules) caracteres += "abcdefghijklmnopqrstuvwxyz";
if (inclureMajuscules) caracteres += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
if (inclureChiffres)   caracteres += "0123456789";
if (inclureSpeciaux)   caracteres += "!@#$%&*?";

Après ce bloc, la variable caracteres contient uniquement les caractères que l'utilisateur a autorisés. Si toutes les cases sont cochées, la chaîne fait 71 caractères. Si une seule case est cochée, elle est plus courte. Si aucune case n'est cochée, elle est vide — et c'est un problème qu'on doit gérer.


Étape 6 — Refuser les cas absurdes

Si la chaîne caracteres est vide, impossible de générer un mot de passe. Il faut prévenir l'utilisateur avant d'essayer.

if (caracteres == "")
{
    MessageBox.Show("Sélectionne au moins un type de caractère.",
                    "Aucune option choisie",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Warning);
    lblMessage.Text = "Erreur : aucune option cochée.";
    return;
}

Le return est important : il interrompt la méthode. Sans lui, le code continuerait et planterait à l'étape suivante en essayant de lire un caractère dans une chaîne vide.

💡 Principe à retenir : valide toujours tes entrées avant de t'en servir. Plus tôt tu détectes une situation impossible, plus le message d'erreur est clair pour l'utilisateur.


Étape 7 — Générer le mot de passe

C'est le cœur de la logique. On va tirer aléatoirement, longueur fois, un caractère dans la chaîne caracteres, et le concaténer au résultat.

Random rnd = new Random();
string motDePasse = "";

for (int i = 0; i < longueur; i++)
{
    int index = rnd.Next(caracteres.Length);
    motDePasse += caracteres[index];
}

Décortiquons

  • new Random() crée un générateur de nombres aléatoires
  • rnd.Next(caracteres.Length) retourne un entier entre 0 (inclus) et caracteres.Length (exclu) — exactement la plage des indices valides de la chaîne
  • caracteres[index] extrait le caractère à cet indice
  • motDePasse += … ajoute ce caractère à la fin du résultat
  • La boucle for répète l'opération longueur fois

⚠️ Remarque importante (sécurité réelle) : Random est pseudo-aléatoire, pas cryptographiquement sûr. Pour ce projet pédagogique, c'est suffisant. Pour une vraie application qui génère de vrais mots de passe à utiliser, on utiliserait RandomNumberGenerator de l'espace de noms System.Security.Cryptography. À garder en tête pour la suite.


Étape 8 — Afficher le résultat

txtResultat.Text = motDePasse;
lblMessage.Text  = $"Mot de passe de {longueur} caractères généré.";

L'interpolation $"…" permet d'insérer la valeur de longueur directement dans la chaîne. C'est l'équivalent moderne et lisible de la concaténation "… " + longueur + " …".


Le code complet de l'événement

Récapitulons tout en un seul bloc — c'est ce que tu dois avoir dans Form1.cs :

private void btnGenerer_Click(object sender, EventArgs e)
{
    int longueur = (int)numLongueur.Value;

    string caracteres = "";
    if (chkMinuscules.Checked) caracteres += "abcdefghijklmnopqrstuvwxyz";
    if (chkMajuscules.Checked) caracteres += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    if (chkChiffres.Checked)   caracteres += "0123456789";
    if (chkSpeciaux.Checked)   caracteres += "!@#$%&*?";

    if (caracteres == "")
    {
        MessageBox.Show("Sélectionne au moins un type de caractère.",
                        "Aucune option choisie",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Warning);
        lblMessage.Text = "Erreur : aucune option cochée.";
        return;
    }

    Random rnd = new Random();
    string motDePasse = "";

    for (int i = 0; i < longueur; i++)
    {
        int index = rnd.Next(caracteres.Length);
        motDePasse += caracteres[index];
    }

    txtResultat.Text = motDePasse;
    lblMessage.Text  = $"Mot de passe de {longueur} caractères généré.";
}

Lance ton application. Coche les options, choisis une longueur, clique Générer. Tu dois voir un mot de passe différent à chaque clic.


🧪 Tests à effectuer

Vérifie systématiquement les cas suivants avant de considérer ton app comme terminée :

Test Résultat attendu
Toutes cases cochées, longueur 12 Mot de passe mixte de 12 caractères
Seulement chiffres, longueur 6 Mot de passe de 6 chiffres
Aucune case cochée, clic Message d'erreur, pas de plantage
Longueur 4 Mot de passe court généré
Longueur 64 Mot de passe long généré
Deux clics consécutifs Deux mots de passe différents

📝 Version minimale obligatoire

Pour valider le projet, ton application doit :

  • générer un mot de passe au clic
  • respecter les choix de l'utilisateur (longueur + types de caractères)
  • afficher le résultat dans la zone prévue
  • gérer au moins le cas « aucune case cochée »

🌟 Bonus possibles

Si tu termines tôt ou si tu veux pousser :

  • Bouton Copier — copie le mot de passe dans le presse-papiers (Clipboard.SetText(txtResultat.Text);)
  • Bouton Effacer — vide le résultat et remet les options par défaut
  • Indicateur de force — change la couleur de fond du résultat (rouge si court, orange si moyen, vert si long et varié)
  • Au moins un de chaque — force le mot de passe à contenir au moins un caractère de chaque catégorie cochée (utile pour les sites qui exigent ça)
  • Polissage — police monospace pour le résultat, alignement des contrôles, marges, raccourci clavier Entrée pour générer

✅ Critères de réussite

  • ✅ L'interface est claire et lisible
  • ✅ Les contrôles sont renommés avec des préfixes cohérents
  • ✅ Le bouton Générer fonctionne
  • ✅ Les options sont respectées dans le résultat
  • ✅ Les cas d'erreur affichent un message utile
  • ✅ Le code est indenté et lisible
  • ✅ Les tests du tableau ci-dessus passent tous

💡 Conseils de méthode

Travaille dans cet ordre, pas autrement :

  1. Interface seulement, sans aucun code
  2. Test du bouton avec un simple MessageBox.Show
  3. Lecture des valeurs (avec un MessageBox temporaire pour vérifier)
  4. Logique de génération
  5. Affichage du résultat
  6. Gestion d'erreur
  7. Polissage et bonus

À chaque étape, lance l'application et vérifie. Si ça marche, passe à la suivante. Si ça ne marche pas, ne va pas plus loin — règle le problème immédiatement. Empiler des bugs sans les voir, c'est la recette pour ne plus savoir où chercher.


🤔 Défi réflexion

Réponds par écrit à la question suivante en quelques lignes :

Qu'est-ce qui rend un mot de passe sécurisé ?

Dans ta réponse, explique :

  • le rôle de la longueur — pourquoi un mot de passe de 6 caractères est-il facile à casser, même mixte ?
  • l'intérêt de mélanger les types de caractères — qu'est-ce que ça change pour un attaquant ?
  • les limites d'un mot de passe aléatoire — qu'est-ce qui ne dépend pas du mot de passe lui-même (fuites de données, phishing, gestionnaire de mots de passe…) ?

✍️ À retenir

  • Une application Windows Forms est composée d'une fenêtre (Form), de contrôles posés dessus, et de méthodes C# qui réagissent à des événements.
  • Le concepteur visuel de Rider permet de dessiner l'interface à la souris ; le code derrière se trouve dans Form1.cs.
  • Renommer ses contrôles avec une convention (btn, txt, chk, lbl, num…) est indispensable pour rester lisible.
  • Double-cliquer sur un contrôle crée la méthode liée à son événement principal (Click pour un bouton).
  • Toujours valider les entrées utilisateur avant de les utiliser, avec un message d'erreur clair en cas de problème.
  • Avancer par petits pas validés est plus rapide que coder en bloc et chercher où ça plante.

Pour aller plus loin