Programmation Graphique et Événementielle en Java et C#

Bienvenue dans le Cours

Ce cours complet de Programmation Graphique et Événementielle en Java et C# couvre les fondamentaux du développement d'interfaces graphiques (GUI) dans les deux langages les plus utilisés dans l'industrie logicielle. Que vous soyez débutant ou développeur expérimenté souhaitant approfondir vos connaissances, ce cours vous guidera pas à pas à travers les concepts, les frameworks et les meilleures pratiques.

Objectif du cours

Maîtriser la création d'applications graphiques interactives en Java (AWT, Swing) et en C# (Windows Forms, WPF), comprendre le modèle événementiel, et être capable de développer des projets complets intégrant gestion d'interfaces, événements utilisateur et architecture logicielle.

Contenu du cours

ChapitreThèmeLangage
1Introduction à la Programmation GraphiqueGénéral
2Environnements de DéveloppementJava & C#
3Programmation Graphique - AWTJava
4Programmation Graphique - SwingJava
5Programmation ÉvénementielleJava
6Programmation Graphique - Windows FormsC#
7Programmation Graphique - WPFC#
8Programmation ÉvénementielleC#
9Projets Complets et SynthèseJava & C#

Prérequis

Java AWT (java.awt) Swing (javax.swing) JavaFX Event Dispatch Thread C# / .NET Windows Forms WPF + XAML .NET MAUI Delegates & Events Comparaison

Figure : Écosystèmes GUI - Java vs C# (.NET)

Chapitre 1 : Introduction à la Programmation Graphique

1.1 Historique et évolution

L'histoire des interfaces graphiques (GUI - Graphical User Interface) remonte aux années 1960, lorsque Douglas Engelbart et son équipe au Stanford Research Institute ont développé les concepts fondamentaux de l'interaction homme-machine moderne. En 1968, lors de la célèbre démonstration "Mother of All Demos", Engelbart a présenté pour la première fois la souris, les fenêtres et les liens hypertextes, posant les bases de l'interface utilisateur moderne que nous connaissons aujourd'hui.

Au cours des années 1970, le Xerox PARC (Palo Alto Research Center) a joué un rôle pionnier avec le développement du Xerox Alto, le premier ordinateur personnel à utiliser une interface graphique complète. Ce travail a directement inspiré Steve Jobs lors de sa visite au PARC en 1979, menant à la création du Macintosh en 1984. Microsoft a introduit Windows en 1985, évoluant progressivement de Windows 1.0 à Windows 11 en passant par Windows 95 qui a révolutionné l'informatique personnelle.

C'est dans ce contexte que la programmation graphique est devenue une compétence essentielle. Les premiers frameworks comme Motif pour X Window System et Tk pour Tcl ont évolué vers des solutions modernes comme Java AWT/Swing, .NET Windows Forms et WPF, permettant aux développeurs de créer des applications riches, interactives et professionnelles.

GUI (Graphical User Interface)

Une interface graphique utilisateur est un type d'interface homme-machine permettant à un utilisateur d'interagir avec un programme informatique par le biais d'éléments visuels (fenêtres, boutons, menus, icônes, champs de texte), plutôt que par des commandes textuelles en ligne de commande. Ce paradigme a révolutionné l'informatique en rendant les logiciels accessibles au grand public.

1.2 Concepts fondamentaux

La programmation graphique repose sur plusieurs piliers fondamentaux. Un composant graphique (widget) est un élément d'interface visuel servant de point d'interaction : boutons, labels, champs de texte, listes, cases à cocher. Un conteneur est un composant capable d'héberger d'autres composants, formant une hiérarchie : une fenêtre contient des panneaux, qui contiennent des boutons. Le gestionnaire de disposition (Layout Manager) organise automatiquement les composants selon des règles prédéfinies, gérant le redimensionnement et l'adaptation à différentes résolutions d'écran.

Concepts Clés
Composant (Widget)  → Élément visuel interactif
Conteneur (Container) → Regroupe d'autres composants
Layout Manager      → Organise les composants automatiquement
Événement (Event)   → Action utilisateur (clic, touche, etc.)
Listener/Handler    → Code exécuté en réponse à un événement

1.3 Paradigme événementiel vs séquentiel

Dans un programme séquentiel, l'exécution suit un flux linéaire prédéfini : l'instruction A s'exécute, puis B, puis C. L'utilisateur n'a que peu d'influence pendant l'exécution. Dans un programme événementiel, le flux est déterminé par les actions de l'utilisateur. Le programme se met en attente et réagit lorsqu'un événement se produit (clic de souris, pression de touche, redimensionnement de fenêtre). Ce paradigme nécessite trois éléments clés : la source d'événement (le composant), l'objet événement (les informations sur l'action), et l'écouteur (le code de réponse).

CritèreSéquentielÉvénementiel
FluxLinéaire, prédéfiniNon déterministe, piloté par les événements
ContrôleProgrammeUtilisateur
InteractivitéLimitéeForte, temps réel
ApplicationsScripts batch, calculsGUI, jeux vidéo, web

Débutant Identification des composants GUI

Observez une application que vous utilisez quotidiennement. Identifiez au moins 15 composants graphiques différents (boutons, menus, barres, etc.) et classez-les en composants de saisie et composants d'affichage.

Par exemple dans un navigateur : barre d'adresse (TextField), bouton retour (Button), onglets (TabbedPane), menu Options (Menu), barre de progression (ProgressBar), liste d'historique (List)...

Moyen Analyse événementielle

Pour une application de votre choix, identifiez 5 événements différents avec : la source, le type d'événement et l'action résultante.

Exemple : clic sur "Envoyer" dans un email → source = btnEnvoyer, type = ActionEvent, résultat = envoi du message. Pensez aux événements clavier, souris, et fenêtre.

Avancé Pseudo-code comparatif

Écrivez le pseudo-code d'une calculatrice simple : (a) en paradigme séquentiel (ligne de commande), (b) en paradigme événementiel (interface graphique). Mettez en évidence les différences structurelles.

En séquentiel : lire() → lire() → lire() → calculer() → afficher(). En événementiel : boucle_principale → attendre_evenement() → si clic_bouton("7") → afficher("7") → si clic("=") → calculer_et_afficher().

Chapitre 2 : Environnements de Développement

2.1 Installation du JDK et compilation Java

Pour développer des applications graphiques en Java, il faut installer le JDK (Java Development Kit) qui contient le compilateur (javac), la machine virtuelle (JVM) et les bibliothèques standard. Deux distributions existent : Oracle JDK (commercial) et OpenJDK (open source, recommandé). L'installation inclut la configuration des variables d'environnement PATH (pour accéder aux commandes java/javac) et JAVA_HOME (chemin d'installation).

Java
// HelloWorld.java - Premier programme graphique Java
import javax.swing.*;

public class HelloWorld {
    public static void main(String[] args) {
        JFrame fenetre = new JFrame("Mon Premier Programme");
        fenetre.setSize(400, 300);
        fenetre.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JLabel label = new JLabel("Bonjour le Monde !");
        label.setHorizontalAlignment(SwingConstants.CENTER);

        fenetre.add(label);
        fenetre.setVisible(true);
    }
}

// Compilation et exécution :
// $ javac HelloWorld.java
// $ java HelloWorld
Important : Utilisez Java 11 LTS ou Java 17 LTS pour la programmation Swing. Vérifiez l'installation avec java -version et javac -version.

2.2 Visual Studio et compilation C#

Pour le développement C#, Visual Studio Community (gratuit) est l'IDE recommandé. Il faut installer la charge de travail "Développement .NET Desktop" qui inclut le SDK .NET, le compilateur C#, le designer Windows Forms/WPF et les outils de débogage. Alternativement, VS Code avec l'extension C# Dev Kit offre une expérience légère et multiplateforme.

C#
using System;
using System.Windows.Forms;

namespace MonPremierProgramme
{
    public class MainForm : Form
    {
        private Label label;

        public MainForm()
        {
            this.Text = "Mon Premier Programme C#";
            this.Size = new System.Drawing.Size(400, 300);

            label = new Label();
            label.Text = "Bonjour le Monde !";
            label.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            label.Dock = DockStyle.Fill;

            this.Controls.Add(label);
            this.FormClosed += (s, e) => Application.Exit();
        }

        [STAThread]
        public static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new MainForm());
        }
    }
}

2.3 IDEs recommandés

IDELangage(s)GratuitGUI Builder
EclipseJava, C/C++OuiWindowBuilder
IntelliJ IDEAJava, KotlinCE oui / PA nonUI Designer
NetBeansJava, PHPOuiMatisse (Swing)
VS CodeMulti-langageOuiExtensions
Visual StudioC#, .NETCommunity ouiWinForms/WPF

Débutant Installation et configuration

Installez le JDK (OpenJDK 17) et configurez les variables d'environnement. Installez aussi Visual Studio Community. Vérifiez avec java -version et créez un projet Windows Forms.

Téléchargez OpenJDK depuis adoptium.net. Pour VS, téléchargez depuis visualstudio.microsoft.com et cochez "Développement .NET Desktop" lors de l'installation.

Avancé Comparaison d'IDEs

Téléchargez deux IDEs, créez le même programme graphique dans chacun, et rédigez un rapport comparatif portant sur la facilité d'installation, le GUI builder, le débogage et la performance.

Comparez par exemple NetBeans vs Eclipse pour Java, ou VS Code vs Visual Studio pour C#. Notez le temps de mise en place, les fonctionnalités d'autocomplétion et l'ergonomie du designer visuel.

Chapitre 3 : Programmation Graphique en Java - AWT

3.1 Architecture AWT

L'AWT (Abstract Window Toolkit) est la première bibliothèque graphique de Java (JDK 1.0, 1995). Elle utilise des composants natifs (heavyweight) : chaque composant AWT est implémenté par le système d'exploitation via le modèle "peer". Un Button AWT sous Windows utilise le contrôle natif Windows, sous macOS le contrôle Cocoa. Cette approche garantit une apparence native mais limite la personnalisation. La hiérarchie de classes AWT est fondamentale : tous les composants héritent de Component, les conteneurs de Container, et les fenêtres de Window/Frame.

Object Component (java.awt) Container (AWT) JComponent (Swing) Window / Frame Panel JPanel JLabel, JButton... Button, TextField (AWT) JButton, JTextField JTable, JTree, JList... Heavyweight (natif) Lightweight (dessiné par Java)

Figure : Hiérarchie des composants GUI Java

Composant Heavyweight vs Lightweight

Un composant heavyweight (AWT) délègue son rendu au système d'exploitation via un "peer" natif. Un composant lightweight (Swing) est entièrement dessiné par Java, offrant une indépendance platforme et une personnalisation complète.

3.2 Layout Managers

Les gestionnaires de disposition organisent automatiquement les composants dans un conteneur. Java AWT/Swing propose cinq layouts principaux, chacun adapté à des besoins spécifiques.

LayoutOrganisationUsage typique
FlowLayoutLigne par ligne, gauche à droiteBarres d'outils, panneaux de boutons
BorderLayout5 zones : N, S, E, O, CentreFenêtres principales, dialogues
GridLayoutGrille régulière (lignes × colonnes)Calculatrices, claviers
CardLayoutComposants empilés (cartes)Assistants (wizards), onglets
GridBagLayoutGrille flexible avec contraintesFormulaires complexes
Java
import java.awt.*;
public class ExempleLayout extends Frame {
    public ExempleLayout() {
        setTitle("Exemple BorderLayout");
        setSize(500, 350);
        setLayout(new BorderLayout(10, 10));
        add(new Button("NORD"), BorderLayout.NORTH);
        add(new Button("SUD"), BorderLayout.SOUTH);
        add(new Button("EST"), BorderLayout.EAST);
        add(new Button("OUEST"), BorderLayout.WEST);
        add(new Button("CENTRE"), BorderLayout.CENTER);
        addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
    }
    public static void main(String[] args) {
        new ExempleLayout().setVisible(true);
    }
}

Débutant Fenêtre de bienvenue AWT

Créez une fenêtre AWT avec un Label (votre nom), un TextField (saisie message), un Button "Afficher" et un Label résultat. Utilisez BorderLayout.

extends Frame → setLayout(new BorderLayout()) → add(labelNom, BorderLayout.NORTH) → add(textField, BorderLayout.CENTER) → add(button, BorderLayout.SOUTH). Ajoutez un ActionListener au bouton.

Moyen Calculatrice AWT

Créez une calculatrice avec deux TextField (opérandes), un Choice (opérateur), un Button "Calculer" et un TextField résultat. Utilisez GridLayout.

Utilisez Double.parseDouble() pour convertir les TextField en nombres. Gérez ArithmeticException pour la division par zéro.

Chapitre 4 : Programmation Graphique en Java - Swing

4.1 Architecture Swing et le pattern MVC

Swing (javax.swing, JDK 1.2, 1998) est le successeur de l'AWT. Tous ses composants sont lightweight (dessinés par Java, pas de composants natifs), offrant une indépendance platforme totale et une personnalisation complète. Les composants Swing commencent par "J" : JFrame, JPanel, JButton, JLabel. Swing repose sur le pattern MVC (Model-View-Controller) : le Model stocke les données, la Vue gère l'affichage, et le Contrôleur traite les interactions.

Model (Données / État) View (Affichage / UI) Controller (Logique / Événements) Mise à jour du modèle Pattern MVC dans Swing

Figure : Le pattern MVC (Model-View-Controller)

SwingUtilities.invokeLater()

Cette méthode garantit que la création et la modification de l'interface graphique Swing s'effectue dans l'Event Dispatch Thread (EDT), le thread dédié au rendu et aux événements. Ne jamais créer/modifier l'interface depuis un autre thread.

4.2 Composants Swing avancés

Swing offre trois catégories de composants : les conteneurs de haut niveau (JFrame, JDialog, JApplet), les conteneurs intermédiaires (JPanel, JScrollPane, JSplitPane, JTabbedPane, JToolBar) et les composants atomiques (JButton, JLabel, JTextField, JTextArea, JCheckBox, JComboBox, JList, JTable, JTree). JTable est particulièrement puissant avec son modèle DefaultTableModel, et JTree permet d'afficher des données hiérarchiques.

Java
import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;

public class AppSwing extends JFrame {
    private JTable table;
    private DefaultTableModel model;

    public AppSwing() {
        setTitle("Application Swing Avancée");
        setSize(800, 500);
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        String[] colonnes = {"Nom", "Prénom", "Âge"};
        model = new DefaultTableModel(colonnes, 0);
        table = new JTable(model);
        table.setRowHeight(25);

        JScrollPane scroll = new JScrollPane(table);
        add(scroll, BorderLayout.CENTER);

        JPanel form = new JPanel(new GridLayout(4, 2, 5, 5));
        form.add(new JLabel("Nom:"));
        JTextField txtNom = new JTextField();
        form.add(txtNom);
        form.add(new JLabel("Prénom:"));
        JTextField txtPrenom = new JTextField();
        form.add(txtPrenom);

        JButton btnAjouter = new JButton("Ajouter");
        btnAjouter.setBackground(new Color(0, 137, 123));
        btnAjouter.setForeground(Color.WHITE);
        btnAjouter.addActionListener(e -> {
            model.addRow(new Object[]{
                txtNom.getText(), txtPrenom.getText()
            });
            txtNom.setText("");
            txtPrenom.setText("");
        });
        form.add(btnAjouter);
        add(form, BorderLayout.NORTH);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() ->
            new AppSwing().setVisible(true));
    }
}

Moyen Jeu de morpion Swing

Créez un morpion (tic-tac-toe) : grille 3×3 de JButton, JLabel (joueur courant), bouton "Nouvelle Partie", détection du gagnant/match nul. Utilisez GridLayout pour la grille.

Utilisez un tableau JButton[3][3]. Alternez "X" et "O" à chaque clic. Après chaque coup, vérifiez les 8 combinaisons gagnantes (3 lignes, 3 colonnes, 2 diagonales).

Chapitre 5 : Programmation Événementielle en Java

5.1 Le modèle de délégation d'événements

Le Delegation Event Model est le mécanisme Java de gestion des événements (introduit JDK 1.1). Il repose sur trois acteurs : l'objet événement (EventObject, contient la source et les données), la source (le composant qui génère l'événement), et l'écouteur (Listener, implémente une interface de callback). Le processus : l'écouteur s'enregistre via addXxxListener() → l'utilisateur interagit → la source crée un EventObject → la source notifie les écouteurs → l'écouteur exécute le handler.

Utilisateur (Clic, Touche...) Source (Composant) Crée EventObject Event Object Données Listener Handler() addXxxListener() → actionPerformed() / mouseClicked() / keyPressed()

Figure : Modèle de délégation d'événements Java

5.2 Event Listeners et Adapters

InterfaceMéthodes principalesAdapter
ActionListeneractionPerformed()Aucune
MouseListener5 méthodes (click, press, release, enter, exit)MouseAdapter
KeyListenerkeyPressed(), keyReleased(), keyTyped()KeyAdapter
WindowListener7 méthodes (opening, closing, activated...)WindowAdapter
ItemListeneritemStateChanged()Aucune
FocusListenerfocusGained(), focusLost()FocusAdapter
Java
// Exemple complet d'événements Swing
btnClic.addActionListener(e -> lblInfo.setText("Bouton cliqué !"));

btnClic.addMouseListener(new MouseAdapter() {
    public void mouseEntered(MouseEvent e) {
        btnClic.setBackground(new Color(0, 137, 123));
        btnClic.setForeground(Color.WHITE);
    }
    public void mouseExited(MouseEvent e) {
        btnClic.setBackground(null);
        btnClic.setForeground(null);
    }
});

txtSaisie.addKeyListener(new KeyAdapter() {
    public void keyReleased(KeyEvent e) {
        lblInfo.setText("Touche : " +
            KeyEvent.getKeyText(e.getKeyCode()));
    }
});

// Fermeture fenêtre avec WindowAdapter
addWindowListener(new WindowAdapter() {
    public void windowClosing(WindowEvent e) {
        System.exit(0);
    }
});

Moyen Traqueur de souris

Créez un JPanel affichant les coordonnées de la souris en temps réel et détectant les clics simples/doubles. Ajoutez un mode dessin libre (tracer des lignes au mouvement de la souris avec bouton pressé).

Utilisez MouseMotionListener (mouseMoved) pour les coordonnées et MouseListener (mouseClicked) pour les clics. Pour le dessin, overridez paintComponent(Graphics g) et utilisez g.drawLine().

Chapitre 6 : Programmation Graphique en C# - Windows Forms

6.1 Introduction à Windows Forms

Windows Forms (WinForms, .NET 1.0, 2002) est le framework Microsoft pour les applications de bureau Windows. Il utilise GDI+ pour le rendu et les contrôles natifs Windows (HWND). Le Form est le conteneur principal, auquel on ajoute des contrôles via la propriété Controls. Visual Studio offre un designer visuel puissant pour créer des interfaces par glisser-déposer, générant automatiquement le code dans un fichier Designer.cs partiel.

6.2 Contrôles Windows Forms

Contrôle C#ClasseÉquivalent Swing
BoutonButtonJButton
LabelLabelJLabel
Zone de texteTextBoxJTextField
Case à cocherCheckBoxJCheckBox
Liste déroulanteComboBoxJComboBox
Grille de donnéesDataGridViewJTable
PanneauPanelJPanel
OngletsTabControlJTabbedPane
Barre de progressionProgressBarJProgressBar
C#
using System;
using System.Windows.Forms;
using System.Drawing;

public class FormulairePrincipal : Form
{
    private TextBox txtNom;
    private ComboBox cboPays;
    private DataGridView dgvDonnees;
    private Label lblStatut;

    public FormulairePrincipal()
    {
        this.Text = "Gestion de Contacts";
        this.Size = new Size(800, 600);
        this.StartPosition = FormStartPosition.CenterScreen;

        Panel panel = new Panel();
        panel.Size = new Size(250, 350);
        panel.BorderStyle = BorderStyle.FixedSingle;

        var lbl = new Label() { Text = "Nom :", Location = new Point(10,20) };
        txtNom = new TextBox() { Location = new Point(10,45), Width = 220 };

        var btn = new Button() { Text = "Ajouter", Location = new Point(10,120) };
        btn.BackColor = Color.Teal;
        btn.ForeColor = Color.White;
        btn.Click += (s, e) => {
            dgvDonnees.Rows.Add(txtNom.Text, cboPays.Text);
            lblStatut.Text = $"Contact ajouté ! Total : {dgvDonnees.RowCount}";
        };

        dgvDonnees = new DataGridView() { Location = new Point(280,20), Size = new Size(480,350) };
        dgvDonnees.Columns.Add("Nom", "Nom");
        dgvDonnees.Columns.Add("Pays", "Pays");

        lblStatut = new Label() { Text = "Prêt", Dock = DockStyle.Bottom };
        panel.Controls.AddRange(new Control[] { lbl, txtNom, btn });
        this.Controls.AddRange(new Control[] { panel, dgvDonnees, lblStatut });
    }

    [STAThread]
    public static void Main() => Application.Run(new FormulairePrincipal());
}

Moyen Calculatrice Windows Forms

Créez une calculatrice avec TableLayoutPanel, boutons 0-9 et opérateurs, TextBox affichage, et gestion des erreurs. Ajoutez un historique des opérations.

Utilisez TableLayoutPanel(4, 4) pour la grille de boutons. Gérez l'événement Click de chaque bouton. Utilisez double.TryParse() pour la conversion. Affichez l'historique dans une ListBox.

Chapitre 7 : Programmation Graphique en C# - WPF

7.1 Introduction à WPF et XAML

WPF (Windows Presentation Foundation), introduit avec .NET 3.0 (2006), utilise DirectX pour le rendu avec accélération matérielle et XAML (eXtensible Application Markup Language) pour la définition déclarative de l'interface. Contrairement à WinForms (natif GDI+), WPF est entièrement vectoriel, permettant des animations, effets de transparence, transformations 3D et une personnalisation visuelle illimitée via les Control Templates et les Styles.

XAML / C#
<!-- MainWindow.xaml -->
<Window x:Class="MonApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        Title="Mon Application WPF" Height="500" Width="700">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="250"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <StackPanel Grid.Column="0" Margin="10">
            <TextBlock Text="Formulaire" FontSize="20" FontWeight="Bold"/>
            <TextBox x:Name="TxtNom" Header="Nom" Margin="0,5" Height="35"/>
            <TextBox x:Name="TxtEmail" Header="Email" Margin="0,5" Height="35"/>
            <ComboBox x:Name="CboPays" Header="Pays" Margin="0,5" Height="35">
                <ComboBoxItem Content="Congo"/>
                <ComboBoxItem Content="France"/>
                <ComboBoxItem Content="Belgique"/>
            </ComboBox>
            <Button Content="Ajouter" Background="#00897b" Foreground="White"
                    Padding="15,8" Click="BtnAjouter_Click" Margin="0,10"/>
        </StackPanel>

        <DataGrid x:Name="GrilleDonnees" Grid.Column="1"
                  AutoGenerateColumns="False" Margin="10">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Nom" Binding="{Binding Nom}"/>
                <DataGridTextColumn Header="Email" Binding="{Binding Email}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

7.2 Data Binding et MVVM

Le Data Binding WPF lie automatiquement une source de données à un contrôle. Les modes : OneWay (source → cible), TwoWay (bidirectionnel), OneTime (au chargement), OneWayToSource (cible → source). Le pattern MVVM (Model-View-ViewModel) sépare les données (Model), l'interface XAML (View) et le ViewModel (expose les données via INotifyPropertyChanged et les commandes via ICommand).

C#
public class ContactViewModel : INotifyPropertyChanged
{
    private string _nom;
    public string Nom {
        get => _nom;
        set { _nom = value; OnPropertyChanged(); }
    }

    public ObservableCollection<Contact> Contacts { get; }

    public ICommand AjouterCommand { get; }

    public ContactViewModel() {
        Contacts = new ObservableCollection<Contact>();
        AjouterCommand = new RelayCommand(AjouterContact);
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string n = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(n));
}
INotifyPropertyChanged

Interface du .NET Framework permettant à un objet de notifier ses abonnés lorsqu'une de ses propriétés change de valeur. C'est le fondement du data binding bidirectionnel dans WPF et le pattern MVVM.

Chapitre 8 : Programmation Événementielle en C#

8.1 Délégués en C#

Un délégué (delegate) est un type référence qui encapsule une méthode avec une signature spécifique (type de retour et paramètres). C'est similaire à un pointeur de fonction typé en C++, mais avec la sécurité du compilateur. Les délégués multicast peuvent pointer vers plusieurs méthodes simultanément (opérateurs += et -=) et constituent le fondement du système d'événements .NET.

C#
// Déclaration d'un type délégué
public delegate double OperationMath(double a, double b);

public class DemoDelegues
{
    public static double Addition(double a, double b) => a + b;
    public static double Multiplication(double a, double b) => a * b;

    // Utilisation basique
    public static void Main()
    {
        OperationMath op = Addition;
        Console.WriteLine(op(5, 3));  // 8

        // Délégué multicast
        OperationMath multiOp = Addition;
        multiOp += Multiplication;
        multiOp(5, 3); // Appelle Addition puis Multiplication

        // Func (délégué générique intégré)
        Func<double, double, double> moyenne = (a, b) => (a + b) / 2;
        Console.WriteLine(moyenne(10, 20));  // 15

        // Action (délégué sans retour)
        Action<string> logger = Console.WriteLine;
        logger += msg => File.AppendAllText("log.txt", msg);
        logger("Application démarrée"); // Écrit dans console ET fichier
    }
}

8.2 Événements et Event Handlers

Les événements (event) C# sont construits sur les délégués. Le mot-clé event garantit l'encapsulation (seuls += et -= autorisés depuis l'extérieur). Le modèle publication/abonnement : l'éditeur déclare l'événement et le déclenche, l'abonné s'inscrit avec += et fournit un handler. Le framework fournit EventHandler et EventHandler pour la majorité des cas.

C#
public class Thermometre
{
    public event EventHandler<TemperatureArgs> TemperatureCritique;
    private double _temperature;

    public double Temperature {
        set {
            _temperature = value;
            if (_temperature >= 100)
                TemperatureCritique?.Invoke(this,
                    new TemperatureArgs(_temperature, "Ébullition !"));
        }
    }
}

// Abonné
var thermo = new Thermometre();
thermo.TemperatureCritique += (sender, e) => {
    Console.WriteLine($"ALERTE : {e.Message} ({e.Temperature}C)");
};
thermo.Temperature = 100;  // Déclenche l'événement

Moyen Système de notifications

Créez un Serveur avec événements ConnexionPerdue, UtilisateurConnecté, Erreur. Créez des handlers (Logger, AlerteurEmail, TableauDeBord). Simulez une session complète.

Utilisez des EventArgs personnalisés pour chaque type. Le Logger écrit dans la console, l'AlerteurEmail simule l'envoi d'un email, le TableauDeBord met à jour un compteur.

Chapitre 9 : Projets Complets et Synthèse

9.1 Synthèse comparative

CritèreJava SwingC# WinFormsC# WPF
ArchitectureLightweight, JavaHeavyweight, natifLightweight, DirectX
Data BindingBasiqueBasiqueTrès puissant
MultiplateformeOui (JVM)Non (Windows)Non (Windows)
ApprentissageModéréFacileDifficile
PersonnalisationLook and FeelLimitéeComplète
AnimationsManuellesLimitéesNatives
PerformanceBonneBonneExcellente

9.2 Projet : Calculatrice Java Swing

Java
public class Calculatrice extends JFrame {
    private JTextField ecran = new JTextField("0");
    private double premierNombre = 0;
    private String operateur = "";
    private boolean nouveauNombre = true;

    public Calculatrice() {
        setTitle("Calculatrice Java Swing");
        setSize(350, 450);
        ecran.setEditable(false);
        ecran.setFont(new Font("Arial", Font.BOLD, 28));
        ecran.setHorizontalAlignment(JTextField.RIGHT);
        add(ecran, BorderLayout.NORTH);

        String[] btns = {"C","←","%","÷","7","8","9","×",
                         "4","5","6","-","1","2","3","+","+/-","0",".","="};
        JPanel panel = new JPanel(new GridLayout(5, 4, 5, 5));
        for (String txt : btns) {
            JButton btn = new JButton(txt);
            btn.setFont(new Font("Arial", Font.BOLD, 18));
            if (txt.equals("=")) {
                btn.setBackground(new Color(0, 137, 123));
                btn.setForeground(Color.WHITE);
            }
            btn.addActionListener(e -> gererClic(txt));
            panel.add(btn);
        }
        add(panel);
    }

    private void gererClic(String txt) {
        if (txt.matches("[0-9]")) {
            ecran.setText(nouveauNombre ? txt : ecran.getText() + txt);
            nouveauNombre = false;
        } else if (txt.equals("=")) {
            double b = Double.parseDouble(ecran.getText());
            double r = switch(operateur) {
                case "+" -> premierNombre + b;
                case "-" -> premierNombre - b;
                case "×" -> premierNombre * b;
                case "÷" -> b != 0 ? premierNombre / b : throw new ArithmeticException();
                default -> b;
            };
            ecran.setText(String.valueOf(r));
            nouveauNombre = true;
        } else if (txt.matches("[+\\-×÷%]")) {
            premierNombre = Double.parseDouble(ecran.getText());
            operateur = txt;
            nouveauNombre = true;
        } else if (txt.equals("C")) {
            ecran.setText("0"); operateur = ""; nouveauNombre = true;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Calculatrice().setVisible(true));
    }
}

9.3 Perspectives

L'avenir de la programmation graphique s'oriente vers le multiplateforme (.NET MAUI, JavaFX, Flutter), les interfaces modernes (Material Design, Fluent Design) et l'intelligence artificielle pour la génération d'interfaces. Les concepts fondamentaux de ce cours (MVC/MVVM, gestion d'événements, data binding) restent applicables quelle que soit la technologie.

Conseil : La maîtrise des concepts fondamentaux abordés dans ce cours (architecture événementielle, patterns MVC/MVVM, layout managers, data binding) constitue une base solide pour évoluer vers les technologies modernes comme .NET MAUI, JavaFX, Flutter ou React Native.

Avancé Application de gestion de bibliothèque

Créez une application complète (Java ou C#) avec gestion des livres, emprunteurs et prêts. Utilisez des collections, sérialisation et une interface professionnelle avec menus, tableaux et formulaires.

Structurez avec des classes Livre, Emprunteur, Pret. Utilisez ArrayList ou List. Pour la persistance, utilisez ObjectInputStream/ObjectOutputStream (Java) ou XmlSerializer (C#).