📑 TabControl e DataGridView in Windows Forms

Crea interfacce multi-scheda e visualizza dati in tabelle professionali

🎯 Cosa Imparerai in Questa Lezione

Hai imparato i controlli base di Windows Forms. Ora è il momento di creare
interfacce professionali con più pagine e tabelle di dati!
Pensa a programmi come Excel con le sue schede in basso, o a gestionali
con sezioni diverse. Oggi imparerai a crearli! 🚀

✨ I Nuovi Super-Controlli

📑 TabControl

Crea schede multiple come Excel! Ogni scheda può contenere
controlli diversi. Perfetto per organizzare app complesse.

Es: Scheda “Anagrafica” | Scheda “Voti” | Scheda “Statistiche”

📊 DataGridView

Mostra dati in formato tabella come Excel! Colonne, righe,
ordinamento. L’utente può modificare, aggiungere, eliminare.

Es: Tabella studenti con Nome | Cognome | Voto | Classe

📦 Panel e FlowLayoutPanel

Contenitori per organizzare altri controlli. Panel è fisso,
FlowLayoutPanel dispone automaticamente i controlli in fila.

Es: Raggruppare tutti i pulsanti in un Panel in fondo al form

📚 Prerequisiti

Prima di iniziare, dovresti aver completato:

  • ✅ Tutti i controlli base (TextBox, ListBox, ComboBox)
  • ✅ Gestione eventi multipli
  • ✅ RadioButton e CheckBox

📑 Cos’è il TabControl?

🤔 Analogia della Vita Reale

Hai presente i quaderni con i separatori colorati per dividere
le materie? O un’agenda con schede per mesi diversi?
Il TabControl è esattamente questo: ti permette di creare più “pagine”
nella stessa finestra!

💡 Esempi di TabControl nel Mondo Reale

  • Excel: Foglio1 | Foglio2 | Foglio3 (in basso)
  • Browser: Schede multiple per siti diversi
  • Impostazioni Windows: Sistema | Rete | Privacy
  • Gestionale Studenti: Anagrafica | Voti | Presenze
🎯 Quando Usare TabControl

✅ USA quando:

  • Hai molti controlli da organizzare
  • L’app ha sezioni logiche separate
  • Vuoi un’interfaccia pulita e ordinata
❌ NON usare quando:

  • Hai solo 2-3 controlli semplici
  • Le sezioni sono troppo collegate
  • L’utente deve vedere tutto insieme

📝 Esercizio 1: Gestionale Studenti con TabControl

▶ Obiettivo

Creare un’applicazione per gestire studenti con 3 schede diverse:
una per l’anagrafica, una per i voti, e una per le statistiche. Ogni scheda
avrà controlli specifici!

🎯 Cosa Imparerai:

  • Creare un TabControl con più schede
  • Aggiungere controlli diversi in ogni scheda
  • Navigare tra le schede via codice
  • Passare dati tra schede diverse
1

Crea l’Interfaccia con TabControl

📝 Procedura Step-by-Step:

  1. Trascina un TabControl dalla Toolbox sul form
  2. Ridimensionalo per occupare quasi tutto il form
  3. Vedrai 2 schede di default: tabPage1 e tabPage2
  4. Per aggiungere una terza scheda:
    • Clicca con il tasto destro sul TabControl
    • Seleziona “Add Tab”
    • Oppure: vai in Properties → TabPages → clicca … → Add
  5. Rinomina le schede:
    • Seleziona tabPage1 → Properties → Text = “Anagrafica”
    • Seleziona tabPage2 → Properties → Text = “Voti”
    • Seleziona tabPage3 → Properties → Text = “Statistiche”
🎨 Aggiungi Controlli in Ogni Scheda:

📄 SCHEDA 1 – Anagrafica:

  • Label: “Nome:”
  • TextBox: txt_nome
  • Label: “Cognome:”
  • TextBox: txt_cognome
  • Label: “Classe:”
  • ComboBox: cmb_classe (1A, 2A, 3A, 4A, 5A)
  • Button: btn_salva_studente (testo: “Salva Studente”)

📊 SCHEDA 2 – Voti:

  • Label: “Materia:”
  • TextBox: txt_materia
  • Label: “Voto:”
  • NumericUpDown: num_voto (Minimum=1, Maximum=10)
  • Button: btn_aggiungi_voto (testo: “Aggiungi Voto”)
  • ListBox: lst_voti (per vedere i voti inseriti)

📈 SCHEDA 3 – Statistiche:

  • Label: lbl_media (testo: “Media: –“)
  • Label: lbl_voto_max (testo: “Voto Max: –“)
  • Label: lbl_voto_min (testo: “Voto Min: –“)
  • Button: btn_calcola_statistiche (testo: “Calcola”)

2

Il Codice Completo

GestionaleStudenti.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace GestionaleStudenti
{
    public partial class Form1 : Form
    {
        // Lista per memorizzare i voti
        private List voti = new List();
        
        // Variabili per i dati studente
        private string nomeStudente = "";
        private string cognomeStudente = "";
        private string classeStudente = "";

        public Form1()
        {
            InitializeComponent();
            
            // Popola la ComboBox delle classi
            cmb_classe.Items.AddRange(new string[] { "1A", "2A", "3A", "4A", "5A" });
            cmb_classe.SelectedIndex = 0; // Seleziona il primo
        }

        // ═══════════════════════════════════════════
        // SCHEDA 1: SALVA DATI STUDENTE
        // ═══════════════════════════════════════════
        private void btn_salva_studente_Click(object sender, EventArgs e)
        {
            // Valida che i campi siano compilati
            if (string.IsNullOrWhiteSpace(txt_nome.Text))
            {
                MessageBox.Show("Inserisci il nome!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txt_nome.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(txt_cognome.Text))
            {
                MessageBox.Show("Inserisci il cognome!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txt_cognome.Focus();
                return;
            }

            // Salva i dati
            nomeStudente = txt_nome.Text.Trim();
            cognomeStudente = txt_cognome.Text.Trim();
            classeStudente = cmb_classe.SelectedItem.ToString();

            // Conferma
            MessageBox.Show($"Studente salvato:\n{cognomeStudente} {nomeStudente}\nClasse: {classeStudente}", 
                          "Successo", 
                          MessageBoxButtons.OK, 
                          MessageBoxIcon.Information);

            // NAVIGA AUTOMATICAMENTE ALLA SCHEDA VOTI
            tabControl1.SelectedIndex = 1; // 0=Anagrafica, 1=Voti, 2=Statistiche
        }

        // ═══════════════════════════════════════════
        // SCHEDA 2: AGGIUNGI VOTO
        // ═══════════════════════════════════════════
        private void btn_aggiungi_voto_Click(object sender, EventArgs e)
        {
            // Controlla che ci sia uno studente salvato
            if (string.IsNullOrEmpty(nomeStudente))
            {
                MessageBox.Show("Prima salva i dati dello studente nella scheda Anagrafica!", 
                              "Attenzione", 
                              MessageBoxButtons.OK, 
                              MessageBoxIcon.Warning);
                
                // Torna alla scheda Anagrafica
                tabControl1.SelectedIndex = 0;
                return;
            }

            // Valida materia
            if (string.IsNullOrWhiteSpace(txt_materia.Text))
            {
                MessageBox.Show("Inserisci la materia!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txt_materia.Focus();
                return;
            }

            // Prendi il voto
            double voto = (double)num_voto.Value;

            // Aggiungi alla lista
            voti.Add(voto);

            // Mostra nella ListBox
            lst_voti.Items.Add($"{txt_materia.Text}: {voto}");

            // Pulisci i campi per il prossimo inserimento
            txt_materia.Clear();
            num_voto.Value = 6; // Reset a 6
            txt_materia.Focus();
        }

        // ═══════════════════════════════════════════
        // SCHEDA 3: CALCOLA STATISTICHE
        // ═══════════════════════════════════════════
        private void btn_calcola_statistiche_Click(object sender, EventArgs e)
        {
            // Controlla che ci siano voti
            if (voti.Count == 0)
            {
                MessageBox.Show("Non ci sono voti da calcolare!\nAggiungi dei voti nella scheda Voti.", 
                              "Attenzione", 
                              MessageBoxButtons.OK, 
                              MessageBoxIcon.Warning);
                
                // Vai alla scheda Voti
                tabControl1.SelectedIndex = 1;
                return;
            }

            // Calcola statistiche usando LINQ
            double media = voti.Average();
            double votoMax = voti.Max();
            double votoMin = voti.Min();

            // Mostra risultati
            lbl_media.Text = $"Media: {media:F2}"; // F2 = 2 decimali
            lbl_voto_max.Text = $"Voto Max: {votoMax}";
            lbl_voto_min.Text = $"Voto Min: {votoMin}";

            // Cambia colore in base alla media
            if (media >= 6)
            {
                lbl_media.ForeColor = Color.Green;
            }
            else
            {
                lbl_media.ForeColor = Color.Red;
            }
        }
    }
}

3

🎬 Come Funziona l’App

📋 Flusso Completo:

1️⃣ Scheda Anagrafica:

  • L’utente inserisce: Nome = “Mario”, Cognome = “Rossi”, Classe = “3A”
  • Clicca “Salva Studente”
  • L’app passa automaticamente alla scheda Voti

2️⃣ Scheda Voti:

  • Inserisce: Materia = “Matematica”, Voto = 8
  • Clicca “Aggiungi Voto” → appare “Matematica: 8” nella ListBox
  • Inserisce: Materia = “Italiano”, Voto = 7
  • Inserisce: Materia = “Inglese”, Voto = 9
  • Totale: 3 voti inseriti

3️⃣ Scheda Statistiche:

  • Clicca “Calcola”
  • Media: 8.00 (verde perché ≥ 6)
  • Voto Max: 9
  • Voto Min: 7

📚 Concetti Chiave – TabControl

tabControl.SelectedIndex
Cambia scheda via codice. Gli indici partono da 0.

tabControl1.SelectedIndex = 0;  // Prima scheda
tabControl1.SelectedIndex = 1;  // Seconda scheda
tabControl1.SelectedIndex = 2;  // Terza scheda

// Ottieni l'indice della scheda corrente
int schemaCorrente = tabControl1.SelectedIndex;

LINQ: .Average(), .Max(), .Min()
Metodi per calcolare statistiche su liste di numeri

List numeri = new List { 5, 8, 3, 9, 7 };

double media = numeri.Average();      // 6.4
double massimo = numeri.Max();        // 9
double minimo = numeri.Min();         // 3
int conteggio = numeri.Count;         // 5
double somma = numeri.Sum();          // 32

string.IsNullOrWhiteSpace()
Controlla se una stringa è vuota, null, o contiene solo spazi

string.IsNullOrWhiteSpace("")          // true
string.IsNullOrWhiteSpace("   ")       // true (solo spazi)
string.IsNullOrWhiteSpace("Mario")     // false
string.IsNullOrWhiteSpace(null)        // true

📊 Cos’è il DataGridView?

🤔 Pensa a Excel!

Il DataGridView è praticamente una tabella Excel
dentro la tua applicazione! Ha colonne, righe, e puoi aggiungere/modificare/eliminare
dati direttamente come in un foglio di calcolo.

💡 Esempi di DataGridView

  • Registro Studenti: Nome | Cognome | Classe | Email | Telefono
  • Catalogo Prodotti: Codice | Nome | Prezzo | Quantità | Categoria
  • Lista Film: Titolo | Anno | Regista | Durata | Genere
  • Elenco Auto: Marca | Modello | Anno | Prezzo | Carburante
🎯 Vantaggi del DataGridView

  • ✅ Visualizza molti dati in poco spazio
  • ✅ L’utente può ordinare cliccando sulle colonne
  • ✅ Supporta modifica diretta delle celle
  • ✅ Puoi aggiungere/rimuovere righe facilmente
  • ✅ Selezione multipla di righe
  • ✅ Scrollbar automatici quando ci sono molti dati

📚 Esercizio 2: Registro Libri con DataGridView

▶ Obiettivo

Creare un’applicazione per gestire una biblioteca personale.
I libri vengono mostrati in una tabella dove puoi aggiungere, rimuovere e
modificare i libri direttamente!

1

Crea l’Interfaccia

🎨 Controlli da Aggiungere:

  • DataGridView: dgv_libri
    • Ridimensionalo per occupare la maggior parte del form
    • Properties → Dock = Fill (riempie tutto lo spazio)
  • Panel (in fondo con Dock = Bottom) contenente:
    • TextBox: txt_titolo (placeholder: “Titolo”)
    • TextBox: txt_autore (placeholder: “Autore”)
    • NumericUpDown: num_anno (Minimum=1900, Maximum=2025)
    • TextBox: txt_genere (placeholder: “Genere”)
    • Button: btn_aggiungi (testo: “Aggiungi Libro”)
    • Button: btn_rimuovi (testo: “Rimuovi Selezionato”)

2

Codice Completo

RegistroLibri.cs
using System;
using System.Windows.Forms;

namespace RegistroLibri
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            
            // Inizializza il DataGridView
            ImpostaDataGridView();
        }

        // ═══════════════════════════════════════════
        // SETUP INIZIALE: Crea le colonne
        // ═══════════════════════════════════════════
        private void ImpostaDataGridView()
        {
            // Pulisci colonne esistenti (se ci sono)
            dgv_libri.Columns.Clear();
            
            // Aggiungi colonne manualmente
            dgv_libri.Columns.Add("Titolo", "Titolo");
            dgv_libri.Columns.Add("Autore", "Autore");
            dgv_libri.Columns.Add("Anno", "Anno");
            dgv_libri.Columns.Add("Genere", "Genere");
            
            // Imposta larghezza colonne
            dgv_libri.Columns["Titolo"].Width = 250;
            dgv_libri.Columns["Autore"].Width = 200;
            dgv_libri.Columns["Anno"].Width = 80;
            dgv_libri.Columns["Genere"].Width = 150;
            
            // Impostazioni visualizzazione
            dgv_libri.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
            dgv_libri.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dgv_libri.MultiSelect = false; // Seleziona una riga alla volta
            dgv_libri.AllowUserToAddRows = false; // Nascondi riga vuota in fondo
            
            // Aggiungi alcuni libri di esempio
            AggiungiLibriDiEsempio();
        }

        // ═══════════════════════════════════════════
        // AGGIUNGI LIBRI DI ESEMPIO ALL'AVVIO
        // ═══════════════════════════════════════════
        private void AggiungiLibriDiEsempio()
        {
            dgv_libri.Rows.Add("Il Signore degli Anelli", "J.R.R. Tolkien", 1954, "Fantasy");
            dgv_libri.Rows.Add("1984", "George Orwell", 1949, "Distopico");
            dgv_libri.Rows.Add("Harry Potter e la Pietra Filosofale", "J.K. Rowling", 1997, "Fantasy");
        }

        // ═══════════════════════════════════════════
        // PULSANTE: Aggiungi Nuovo Libro
        // ═══════════════════════════════════════════
        private void btn_aggiungi_Click(object sender, EventArgs e)
        {
            // Validazione campi obbligatori
            if (string.IsNullOrWhiteSpace(txt_titolo.Text))
            {
                MessageBox.Show("Inserisci il titolo del libro!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txt_titolo.Focus();
                return;
            }

            if (string.IsNullOrWhiteSpace(txt_autore.Text))
            {
                MessageBox.Show("Inserisci l'autore!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txt_autore.Focus();
                return;
            }

            // Prendi i dati dai controlli
            string titolo = txt_titolo.Text.Trim();
            string autore = txt_autore.Text.Trim();
            int anno = (int)num_anno.Value;
            string genere = txt_genere.Text.Trim();
            
            // Se genere è vuoto, metti "Non specificato"
            if (string.IsNullOrWhiteSpace(genere))
            {
                genere = "Non specificato";
            }

            // AGGIUNGI LA RIGA AL DATAGRIDVIEW
            dgv_libri.Rows.Add(titolo, autore, anno, genere);

            // Pulisci i campi per il prossimo inserimento
            txt_titolo.Clear();
            txt_autore.Clear();
            num_anno.Value = DateTime.Now.Year; // Anno corrente
            txt_genere.Clear();
            txt_titolo.Focus(); // Rimetti focus sul titolo

            // Messaggio di conferma
            MessageBox.Show($"Libro '{titolo}' aggiunto con successo!", 
                          "Successo", 
                          MessageBoxButtons.OK, 
                          MessageBoxIcon.Information);
        }

        // ═══════════════════════════════════════════
        // PULSANTE: Rimuovi Libro Selezionato
        // ═══════════════════════════════════════════
        private void btn_rimuovi_Click(object sender, EventArgs e)
        {
            // Controlla che ci sia una riga selezionata
            if (dgv_libri.SelectedRows.Count == 0)
            {
                MessageBox.Show("Seleziona un libro da rimuovere!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            // Prendi la riga selezionata
            DataGridViewRow rigaSelezionata = dgv_libri.SelectedRows[0];
            
            // Prendi il titolo per la conferma
            string titolo = rigaSelezionata.Cells["Titolo"].Value.ToString();

            // Chiedi conferma
            DialogResult risultato = MessageBox.Show(
                $"Sei sicuro di voler eliminare '{titolo}'?", 
                "Conferma Eliminazione",
                MessageBoxButtons.YesNo, 
                MessageBoxIcon.Question);

            if (risultato == DialogResult.Yes)
            {
                // RIMUOVI LA RIGA
                dgv_libri.Rows.Remove(rigaSelezionata);
                
                MessageBox.Show("Libro rimosso!", "Successo", 
                              MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        // ═══════════════════════════════════════════
        // EVENTO: Doppio Click su una Riga
        // ═══════════════════════════════════════════
        private void dgv_libri_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
        {
            // Ignora se clicchi sull'header
            if (e.RowIndex < 0) return;

            // Prendi la riga cliccata
            DataGridViewRow riga = dgv_libri.Rows[e.RowIndex];
            
            // Mostra i dettagli del libro
            string dettagli = $"DETTAGLI LIBRO:\n\n" +
                            $"Titolo: {riga.Cells["Titolo"].Value}\n" +
                            $"Autore: {riga.Cells["Autore"].Value}\n" +
                            $"Anno: {riga.Cells["Anno"].Value}\n" +
                            $"Genere: {riga.Cells["Genere"].Value}";
            
            MessageBox.Show(dettagli, "Dettagli Libro", 
                          MessageBoxButtons.OK, MessageBoxIcon.Information);
        }
    }
}

3

🔗 Collegare gli Eventi

📝 Eventi da Collegare:

  1. btn_aggiungi:
    • Event: Click
    • Handler: btn_aggiungi_Click
  2. btn_rimuovi:
    • Event: Click
    • Handler: btn_rimuovi_Click
  3. dgv_libri:
    • Event: CellDoubleClick
    • Handler: dgv_libri_CellDoubleClick

📚 Concetti Chiave - DataGridView

dgv.Columns.Add()
Aggiunge una nuova colonna al DataGridView

// Sintassi: .Add(name, headerText)
dgv.Columns.Add("Nome", "Nome Completo");
dgv.Columns.Add("Eta", "Età");

// Imposta larghezza
dgv.Columns["Nome"].Width = 200;

dgv.Rows.Add()
Aggiunge una nuova riga con i valori specificati

// I valori devono essere nello stesso ordine delle colonne
dgv.Rows.Add("Mario Rossi", 25);
dgv.Rows.Add("Luigi Verdi", 30);

// Numero di righe totali
int totaleRighe = dgv.Rows.Count;

dgv.SelectedRows
Ottiene le righe selezionate dall'utente

// Controlla se c'è una selezione
if (dgv.SelectedRows.Count > 0)
{
    // Prendi la prima riga selezionata
    DataGridViewRow riga = dgv.SelectedRows[0];
    
    // Leggi valore di una cella
    string nome = riga.Cells["Nome"].Value.ToString();
}

dgv.Rows.Remove()
Rimuove una riga specifica dal DataGridView

// Rimuovi riga selezionata
DataGridViewRow riga = dgv.SelectedRows[0];
dgv.Rows.Remove(riga);

// Rimuovi per indice
dgv.Rows.RemoveAt(0); // Rimuove la prima riga

🚀 Esercizio 3: Dashboard Completa

▶ Obiettivo

Crea un'applicazione professionale che combina TabControl + DataGridView!
Sarà un gestionale prodotti con 3 schede: Catalogo (con tabella), Aggiungi Prodotto, Statistiche.

🎯 Sfida Completa:

Questo esercizio integra tutto quello che hai imparato finora!
È un'applicazione di livello professionale.

1

Struttura dell'Applicazione

📑 SCHEDA 1 - Catalogo:

  • DataGridView con colonne: Nome | Prezzo | Quantità | Categoria
  • TextBox per ricerca
  • Button "Cerca"
  • Button "Rimuovi Selezionato"

📝 SCHEDA 2 - Aggiungi Prodotto:

  • TextBox: Nome Prodotto
  • NumericUpDown: Prezzo (0-10000)
  • NumericUpDown: Quantità (0-1000)
  • ComboBox: Categoria (Elettronica, Abbigliamento, Alimentari, Sport)
  • Button "Aggiungi al Catalogo"

📊 SCHEDA 3 - Statistiche:

  • Label: Totale Prodotti
  • Label: Valore Totale Magazzino
  • Label: Prodotto Più Costoso
  • Label: Categoria con Più Prodotti
  • Button "Aggiorna Statistiche"

2

Codice Completo (Versione Pro!)

DashboardProdotti.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace DashboardProdotti
{
    public partial class Form1 : Form
    {
        // Classe per rappresentare un prodotto
        public class Prodotto
        {
            public string Nome { get; set; }
            public decimal Prezzo { get; set; }
            public int Quantita { get; set; }
            public string Categoria { get; set; }

            public decimal ValoreTotale => Prezzo * Quantita;
        }

        // Lista prodotti
        private List prodotti = new List();

        public Form1()
        {
            InitializeComponent();
            
            // Setup iniziale
            ImpostaDataGridView();
            ImpostaComboBoxCategorie();
            AggiungiProdottiDiEsempio();
        }

        // ═══════════════════════════════════════════
        // SETUP: DataGridView
        // ═══════════════════════════════════════════
        private void ImpostaDataGridView()
        {
            dgv_catalogo.Columns.Clear();
            dgv_catalogo.Columns.Add("Nome", "Nome Prodotto");
            dgv_catalogo.Columns.Add("Prezzo", "Prezzo (€)");
            dgv_catalogo.Columns.Add("Quantita", "Quantità");
            dgv_catalogo.Columns.Add("Categoria", "Categoria");
            
            dgv_catalogo.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
            dgv_catalogo.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dgv_catalogo.MultiSelect = false;
            dgv_catalogo.AllowUserToAddRows = false;
        }

        // ═══════════════════════════════════════════
        // SETUP: ComboBox Categorie
        // ═══════════════════════════════════════════
        private void ImpostaComboBoxCategorie()
        {
            cmb_categoria.Items.AddRange(new string[] 
            { 
                "Elettronica", 
                "Abbigliamento", 
                "Alimentari", 
                "Sport" 
            });
            cmb_categoria.SelectedIndex = 0;
        }

        // ═══════════════════════════════════════════
        // AGGIUNGI PRODOTTI DI ESEMPIO
        // ═══════════════════════════════════════════
        private void AggiungiProdottiDiEsempio()
        {
            prodotti.Add(new Prodotto 
            { 
                Nome = "Smartphone", 
                Prezzo = 599.99m, 
                Quantita = 15, 
                Categoria = "Elettronica" 
            });
            
            prodotti.Add(new Prodotto 
            { 
                Nome = "T-Shirt", 
                Prezzo = 19.99m, 
                Quantita = 50, 
                Categoria = "Abbigliamento" 
            });
            
            prodotti.Add(new Prodotto 
            { 
                Nome = "Pasta", 
                Prezzo = 1.50m, 
                Quantita = 200, 
                Categoria = "Alimentari" 
            });

            AggiornaDataGridView();
        }

        // ═══════════════════════════════════════════
        // AGGIORNA IL DATAGRIDVIEW CON I PRODOTTI
        // ═══════════════════════════════════════════
        private void AggiornaDataGridView()
        {
            dgv_catalogo.Rows.Clear();
            
            foreach (Prodotto p in prodotti)
            {
                dgv_catalogo.Rows.Add(
                    p.Nome, 
                    p.Prezzo.ToString("F2"), 
                    p.Quantita, 
                    p.Categoria
                );
            }
        }

        // ═══════════════════════════════════════════
        // SCHEDA 2: AGGIUNGI PRODOTTO
        // ═══════════════════════════════════════════
        private void btn_aggiungi_prodotto_Click(object sender, EventArgs e)
        {
            // Validazione
            if (string.IsNullOrWhiteSpace(txt_nome_prodotto.Text))
            {
                MessageBox.Show("Inserisci il nome del prodotto!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            // Crea nuovo prodotto
            Prodotto nuovo = new Prodotto
            {
                Nome = txt_nome_prodotto.Text.Trim(),
                Prezzo = num_prezzo.Value,
                Quantita = (int)num_quantita.Value,
                Categoria = cmb_categoria.SelectedItem.ToString()
            };

            // Aggiungi alla lista
            prodotti.Add(nuovo);

            // Aggiorna DataGridView
            AggiornaDataGridView();

            // Pulisci campi
            txt_nome_prodotto.Clear();
            num_prezzo.Value = 0;
            num_quantita.Value = 1;
            cmb_categoria.SelectedIndex = 0;

            // Vai alla scheda Catalogo per vedere il prodotto
            tabControl1.SelectedIndex = 0;

            MessageBox.Show($"Prodotto '{nuovo.Nome}' aggiunto!", "Successo", 
                          MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        // ═══════════════════════════════════════════
        // SCHEDA 1: CERCA PRODOTTO
        // ═══════════════════════════════════════════
        private void btn_cerca_Click(object sender, EventArgs e)
        {
            string termineRicerca = txt_ricerca.Text.Trim().ToLower();
            
            if (string.IsNullOrWhiteSpace(termineRicerca))
            {
                // Se vuoto, mostra tutti
                AggiornaDataGridView();
                return;
            }

            // Filtra prodotti
            var prodottiFiltrati = prodotti.Where(p => 
                p.Nome.ToLower().Contains(termineRicerca) ||
                p.Categoria.ToLower().Contains(termineRicerca)
            ).ToList();

            // Aggiorna DataGridView con i risultati filtrati
            dgv_catalogo.Rows.Clear();
            
            foreach (Prodotto p in prodottiFiltrati)
            {
                dgv_catalogo.Rows.Add(p.Nome, p.Prezzo.ToString("F2"), 
                                     p.Quantita, p.Categoria);
            }

            if (prodottiFiltrati.Count == 0)
            {
                MessageBox.Show("Nessun prodotto trovato!", "Ricerca", 
                              MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        // ═══════════════════════════════════════════
        // SCHEDA 1: RIMUOVI PRODOTTO
        // ═══════════════════════════════════════════
        private void btn_rimuovi_Click(object sender, EventArgs e)
        {
            if (dgv_catalogo.SelectedRows.Count == 0)
            {
                MessageBox.Show("Seleziona un prodotto!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            // Prendi la riga selezionata
            int indice = dgv_catalogo.SelectedRows[0].Index;
            string nome = dgv_catalogo.SelectedRows[0].Cells["Nome"].Value.ToString();

            // Conferma
            DialogResult ris = MessageBox.Show(
                $"Eliminare '{nome}'?", 
                "Conferma",
                MessageBoxButtons.YesNo, 
                MessageBoxIcon.Question);

            if (ris == DialogResult.Yes)
            {
                // Rimuovi dalla lista
                prodotti.RemoveAt(indice);
                
                // Aggiorna DataGridView
                AggiornaDataGridView();
            }
        }

        // ═══════════════════════════════════════════
        // SCHEDA 3: CALCOLA STATISTICHE
        // ═══════════════════════════════════════════
        private void btn_aggiorna_statistiche_Click(object sender, EventArgs e)
        {
            if (prodotti.Count == 0)
            {
                MessageBox.Show("Nessun prodotto nel catalogo!", "Attenzione", 
                              MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            // Totale prodotti
            int totale = prodotti.Count;
            lbl_totale_prodotti.Text = $"Totale Prodotti: {totale}";

            // Valore totale magazzino
            decimal valoreTotale = prodotti.Sum(p => p.ValoreTotale);
            lbl_valore_totale.Text = $"Valore Magazzino: {valoreTotale:C}";

            // Prodotto più costoso
            Prodotto piuCostoso = prodotti.OrderByDescending(p => p.Prezzo).First();
            lbl_prodotto_costoso.Text = $"Più Costoso: {piuCostoso.Nome} (€{piuCostoso.Prezzo:F2})";

            // Categoria con più prodotti
            var gruppi = prodotti.GroupBy(p => p.Categoria)
                                .OrderByDescending(g => g.Count())
                                .First();
            lbl_categoria_top.Text = $"Categoria Top: {gruppi.Key} ({gruppi.Count()} prodotti)";
        }
    }
}

📚 Concetti Avanzati Usati

LINQ: .Where()
Filtra una lista in base a una condizione

List numeri = new List { 1, 5, 10, 15, 20 };

// Filtra numeri maggiori di 10
var maggioriDi10 = numeri.Where(n => n > 10).ToList();
// Risultato: { 15, 20 }

// Filtra stringhe che contengono "a"
List nomi = new List { "Mario", "Anna", "Luigi" };
var conA = nomi.Where(n => n.Contains("a")).ToList();
// Risultato: { "Mario", "Anna" }

LINQ: .GroupBy()
Raggruppa elementi in base a una proprietà

// Raggruppa prodotti per categoria
var gruppi = prodotti.GroupBy(p => p.Categoria);

foreach (var gruppo in gruppi)
{
    Console.WriteLine($"{gruppo.Key}: {gruppo.Count()} prodotti");
}

Classi Custom (Prodotto)
Creare classi personalizzate per rappresentare i dati

public class Prodotto
{
    public string Nome { get; set; }
    public decimal Prezzo { get; set; }
    
    // Proprietà calcolata
    public decimal ValoreTotale => Prezzo * Quantita;
}

// Uso
Prodotto p = new Prodotto { Nome = "Telefono", Prezzo = 599 };
Console.WriteLine(p.Nome); // Telefono

📦 Bonus: Panel e Layout

🤔 A Cosa Servono Panel e FlowLayoutPanel?

Sono contenitori per organizzare altri controlli. Invece di
posizionare manualmente 10 pulsanti, li metti in un Panel e sposti solo quello!

📦 Panel

Contenitore fisso. I controlli stanno dove li metti.

💡 Quando usarlo:

  • Raggruppare pulsanti in fondo al form
  • Creare sezioni visive separate
  • Con Dock per posizionamento automatico
🌊 FlowLayoutPanel

Dispone i controlli automaticamente in fila, come il testo.

💡 Quando usarlo:

  • Toolbar con molti pulsanti
  • Gallery di immagini
  • Liste di tag/bottoni dinamici

🎯 Proprietà Importante: Dock

La proprietà Dock attacca un controllo ai bordi del form:

  • Dock = Top: Si attacca in alto, occupa tutta la larghezza
  • Dock = Bottom: Si attacca in fondo
  • Dock = Left/Right: Si attacca a sinistra/destra
  • Dock = Fill: Riempie tutto lo spazio rimanente

💡 Esempio pratico: Panel con pulsanti in fondo (Dock=Bottom) + DataGridView che riempie il resto (Dock=Fill)

🎓 Riepilogo: Cosa Hai Imparato

✨ Nuove Super-Competenze

1️⃣ TabControl

  • Creare schede multiple
  • Navigare tra schede via codice
  • Organizzare app complesse
2️⃣ DataGridView

  • Mostrare dati in tabelle
  • Aggiungere/rimuovere righe
  • Accedere a celle specifiche
3️⃣ LINQ Base

  • .Where() per filtrare
  • .Average(), .Max(), .Min()
  • .GroupBy() per raggruppare
4️⃣ Organizzazione

  • Panel e FlowLayoutPanel
  • Proprietà Dock
  • Layout professionali

🏋️ Esercizi per Allenarsi

💪 Sfide Progressive

⭐ Livello Facile:

  1. Crea un TabControl con 2 schede: "Lista Spesa" e "Totale". Nella prima aggiungi prodotti, nella seconda mostra il totale.
  2. Crea un DataGridView che mostra una lista di film (Titolo, Anno, Genere) con pulsante per aggiungerne di nuovi.

⭐⭐ Livello Medio:

  1. Gestionale Contatti con TabControl (Anagrafica | Lista | Ricerca) e DataGridView per visualizzare tutti i contatti.
  2. Registro Presenze: DataGridView con Nome Studente, Data, Presente/Assente. Aggiungi filtro per cercare assenze di uno studente specifico.

⭐⭐⭐ Livello Difficile:

  1. Crea un Gestionale Videonoleggio completo con: TabControl (Catalogo Film | Prestiti | Statistiche), DataGridView per i film, salvataggio su file CSV.
  2. Dashboard Aziendale: Dipendenti, Progetti, Assegnazioni. Usa TabControl, DataGridView, e LINQ per statistiche avanzate (chi lavora su cosa, progetti più impegnativi, ecc.).

🚀 Prossima Lezione

Hai imparato a organizzare interfacce complesse! Nella prossima lezione scoprirai
Timer e ProgressBar per creare applicazioni che si aggiornano nel
tempo: orologi, cronometri, quiz a tempo e molto altro! ⏱️

Torna in alto