⚡ Gestione Avanzata di Eventi Multipli
Scrivi meno codice, ottieni più funzionalità: il segreto del parametro sender
🎯 Il Salto dalla Lezione 5: Da Oggetti a Eventi Intelligenti
Nella Lezione 5 hai imparato a gestire oggetti complessi come Automobile
con liste List<Automobile>. Hai creato CRUD completo, ordinamenti e statistiche.
Ma c’è un problema che probabilmente hai notato…
// Nel Parco Auto avevi 4 TextBox: Modello, Cilindrata, Prezzo, Anno
// Probabilmente hai scritto qualcosa del genere:
private void txtModello_TextChanged(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtModello.Text))
{
lblErrore.Text = "Il modello è obbligatorio!";
btnAggiungi.Enabled = false;
}
else
{
lblErrore.Text = "";
VerificaCampiCompleti();
}
}
private void txtCilindrata_TextChanged(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtCilindrata.Text))
{
lblErrore.Text = "La cilindrata è obbligatoria!";
btnAggiungi.Enabled = false;
}
else
{
lblErrore.Text = "";
VerificaCampiCompleti();
}
}
// 😱 E devi ripetere questo per txtPrezzo e txtAnno!
// Codice quasi identico copiato 4 volte!
- 📝 Codice duplicato: 4 metodi quasi identici
- 🐛 Difficile manutenzione: Se cambi la logica, devi modificare 4 posti
- ⏱️ Tempo sprecato: Scrivi e debugghi lo stesso codice più volte
- 💥 Errori facili: Dimentichi di aggiornare un metodo = bug
// UN SOLO metodo gestisce TUTTE le TextBox!
private void TextBox_TextChanged(object sender, EventArgs e)
{
// 1️⃣ Scopri QUALE TextBox ha generato l'evento
TextBox textBoxCorrente = (TextBox)sender;
// 2️⃣ Controlla se è vuota
if (string.IsNullOrEmpty(textBoxCorrente.Text))
{
lblErrore.Text = $"Il campo {textBoxCorrente.Name} è obbligatorio!";
btnAggiungi.Enabled = false;
}
else
{
lblErrore.Text = "";
VerificaCampiCompleti();
}
}
// 🎉 Questo metodo funziona per txtModello, txtCilindrata, txtPrezzo, txtAnno
// e qualsiasi altra TextBox che aggiungerai in futuro!
- ✂️ Meno codice: 1 metodo invece di 4 (75% in meno!)
- 🔧 Manutenzione facile: Modifichi un solo punto
- 🚀 Scalabile: Aggiungi nuove TextBox senza scrivere nuovo codice
- 🎯 Professionale: Codice pulito e DRY (Don’t Repeat Yourself)
- ✅ Il Parametro sender: Scoprire quale controllo ha generato l’evento
- ✅ Casting di Controlli: Convertire sender nel tipo specifico (TextBox, Button, etc.)
- ✅ Un Metodo, Più Controlli: Condividere la logica tra controlli simili
- ✅ Validazione Dinamica: Feedback in tempo reale mentre l’utente digita
- ✅ Eventi Multipli sullo Stesso Controllo: Enter, Leave, KeyPress insieme
- ✅ Best Practices: Scrivere codice pulito e manutenibile
Lezione 2 (Eventi Base): Hai usato btnCalcola_Click per un solo pulsante
Lezione 5 (Parco Auto): Hai gestito eventi separati per ogni TextBox
Lezione 6 (Questa): Imparerai a unificare la gestione eventi risparmiando codice
🔑 Il Segreto: Il Parametro “sender”
🧐 Cos’è questo Misterioso “sender”?
Ogni volta che crei un evento in C# (come Button_Click o TextBox_TextChanged),
Visual Studio genera automaticamente un metodo con questa firma:
private void NomeMetodo(object sender, EventArgs e)
{
// Il tuo codice qui
}
Ma cosa sono sender e EventArgs e? Vediamoli uno per uno.
sender è un riferimento all’oggetto (controllo) che ha generato l’evento.
In pratica, ti dice CHI ha chiamato questo metodo.
Immagina di essere un professore con 30 studenti. Quando uno studente alza la mano,
tu devi sapere CHI ha alzato la mano per dargli la parola.
Il parametro sender è proprio questo: ti dice quale studente
(quale controllo) ha “alzato la mano” (generato l’evento).
Senza sender, sapresti solo che “qualcuno ha alzato la mano”, ma non chi.
Con sender, sai esattamente: “È stato Mario!” (È stata txtNome!).
EventArgs e contiene informazioni aggiuntive sull’evento.
Per eventi semplici come Click o TextChanged, di solito è vuoto.
Per eventi più complessi (come KeyPress), contiene dati utili come
“quale tasto è stato premuto”.
sender,che è il più importante per gestire eventi multipli. Vedremo
EventArgs negli esempi avanzati.
🔍 Esempio Pratico: Capire sender
// Crea 3 pulsanti: btnPulsante1, btnPulsante2, btnPulsante3
// Collega tutti e 3 allo STESSO metodo Button_Click
private void Button_Click(object sender, EventArgs e)
{
// sender è un "object" generico
// Dobbiamo dire a C# che in realtà è un Button
Button pulsantePremuto = (Button)sender;
// Ora possiamo usare tutte le proprietà di Button!
MessageBox.Show($"Hai premuto: {pulsantePremuto.Text}");
// Esempi di cosa puoi fare con sender:
string nome = pulsantePremuto.Name; // "btnPulsante1"
string testo = pulsantePremuto.Text; // "Clicca qui"
pulsantePremuto.BackColor = Color.Green; // Cambia colore
pulsantePremuto.Enabled = false; // Disabilita il pulsante
}
- Crea un nuovo Windows Form
- Aggiungi 3 Button:
btnRosso,btnVerde,btnBlu - Imposta la proprietà Text rispettivamente a “Rosso”, “Verde”, “Blu”
- Seleziona tutti e 3 i pulsanti, vai in Proprietà → Eventi → Click
- Seleziona lo stesso metodo per tutti e 3 (es:
Button_Click) - Scrivi questo codice:
private void Button_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
// Cambia il colore del form in base al pulsante premuto
if (btn.Text == "Rosso")
this.BackColor = Color.Red;
else if (btn.Text == "Verde")
this.BackColor = Color.Green;
else if (btn.Text == "Blu")
this.BackColor = Color.Blue;
}
🎉 Risultato: Un solo metodo controlla 3 pulsanti diversi!
Premi ciascun pulsante e guarda il form cambiare colore.
🔄 Casting: Trasformare sender nel Tipo Giusto
❓ Perché sender è “object” e non direttamente “TextBox” o “Button”?
Perché sender può essere qualsiasi tipo di controllo!
Può essere un Button, una TextBox, una ComboBox, un CheckBox, ecc.
Per questo motivo, C# usa il tipo più generico: object.
Ma se è un object, come facciamo ad accedere alle proprietà specifiche di una TextBox
(come .Text) o di un Button (come .Text)?
object sender= Hai ricevuto un pacco generico- Non sai cosa c’è dentro finché non lo apri
(TextBox)sender= Apri il pacco e scopri che è una scarpa Nike- Ora puoi usarla come scarpa (allacciarla, indossarla, ecc.)
🎯 Come Funziona il Casting
// PRIMA del casting: sender è un object generico object sender = ...; // Non puoi usare .Text, .Name, ecc. // CASTING: Trasforma object in TextBox TextBox textBoxCorrente = (TextBox)sender; // DOPO il casting: puoi usare tutte le proprietà di TextBox! string testo = textBoxCorrente.Text; string nome = textBoxCorrente.Name; textBoxCorrente.BackColor = Color.Yellow; int lunghezza = textBoxCorrente.Text.Length;
📖 Tipi di Casting più Comuni
private void TextBox_TextChanged(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
// Ora puoi usare:
string contenuto = txt.Text;
bool vuoto = string.IsNullOrEmpty(txt.Text);
txt.MaxLength = 50;
}
private void Button_Click(object sender, EventArgs e)
{
Button btn = (Button)sender;
// Ora puoi usare:
string testoBtn = btn.Text;
btn.Enabled = false;
btn.BackColor = Color.Gray;
}
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cmb = (ComboBox)sender;
// Ora puoi usare:
string selezione = cmb.SelectedItem.ToString();
int indice = cmb.SelectedIndex;
}
Se provi a fare un casting sbagliato (es: convertire un Button in TextBox),
il programma va in errore (InvalidCastException).
// ❌ SBAGLIATO: Button_Click prova a convertire in TextBox
private void Button_Click(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender; // 💥 ERRORE! sender è un Button, non una TextBox!
}
💡 Regola d’Oro: Fai il casting nel tipo corretto per l’evento:
- TextBox_TextChanged →
(TextBox)sender - Button_Click →
(Button)sender - ComboBox_SelectedIndexChanged →
(ComboBox)sender
💪 Esercizio 1: Form Contatto con Validazione Dinamica
▶ Obiettivo
Creare un form di contatto (Nome, Cognome, Email) che valida i campi in tempo reale
mentre l’utente digita. Il pulsante “Invia” si abilita automaticamente solo quando
tutti i campi sono validi.
- ✅ Usare
senderper gestire più TextBox con un metodo - ✅ Validazione in tempo reale (feedback istantaneo)
- ✅ Abilitare/disabilitare controlli dinamicamente
- ✅ Feedback visivo con colori e messaggi
| Tipo | Name | Proprietà Text | Note |
|---|---|---|---|
| Label | lblNome | “Nome:” | – |
| TextBox | txtNome |
vuoto | Input nome |
| Label | lblCognome | “Cognome:” | – |
| TextBox | txtCognome |
vuoto | Input cognome |
| Label | lblEmail | “Email:” | – |
| TextBox | txtEmail |
vuoto | Input email |
| Label | lblMessaggio |
vuoto | ForeColor: Red, Font: Bold |
| Button | btnInvia |
“Invia” | Enabled: false |
using System;
using System.Drawing;
using System.Windows.Forms;
namespace FormContatto
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// METODO PRINCIPALE: Gestisce TextChanged di TUTTE le TextBox
// ═══════════════════════════════════════════════════════
private void TextBox_TextChanged(object sender, EventArgs e)
{
// 🎯 STEP 1: Scopri QUALE TextBox ha generato l'evento
TextBox textBoxCorrente = (TextBox)sender;
// 🎨 STEP 2: Feedback visivo - mostra quale campo stai compilando
lblMessaggio.Text = $"✏️ Stai scrivendo in: {textBoxCorrente.Name}";
lblMessaggio.ForeColor = Color.Blue;
// ✅ STEP 3: Verifica se TUTTI i campi sono compilati correttamente
bool tuttiCampiValidi = VerificaFormCompleto();
// 🔘 STEP 4: Abilita/disabilita il pulsante in base alla validazione
btnInvia.Enabled = tuttiCampiValidi;
// 💬 STEP 5: Aggiorna il messaggio di stato
if (tuttiCampiValidi)
{
lblMessaggio.Text = "✅ Puoi inviare il form!";
lblMessaggio.ForeColor = Color.Green;
}
else
{
lblMessaggio.Text = "❌ Compila tutti i campi correttamente";
lblMessaggio.ForeColor = Color.Red;
}
}
// ═══════════════════════════════════════════════════════
// METODO HELPER: Controlla se il form è completo e valido
// ═══════════════════════════════════════════════════════
private bool VerificaFormCompleto()
{
// ✅ Validazione Nome: non vuoto e almeno 2 caratteri
bool nomeValido = !string.IsNullOrEmpty(txtNome.Text) &&
txtNome.Text.Trim().Length >= 2;
// ✅ Validazione Cognome: non vuoto e almeno 2 caratteri
bool cognomeValido = !string.IsNullOrEmpty(txtCognome.Text) &&
txtCognome.Text.Trim().Length >= 2;
// ✅ Validazione Email: non vuota E contiene @ E contiene .
bool emailValida = !string.IsNullOrEmpty(txtEmail.Text) &&
txtEmail.Text.Contains("@") &&
txtEmail.Text.Contains(".");
// Restituisci true SOLO se TUTTI e 3 sono validi
return nomeValido && cognomeValido && emailValida;
}
// ═══════════════════════════════════════════════════════
// EVENTO: Click del pulsante Invia
// ═══════════════════════════════════════════════════════
private void btnInvia_Click(object sender, EventArgs e)
{
// Crea il messaggio con i dati inseriti
string messaggio = $"📧 DATI INVIATI CON SUCCESSO!\n\n" +
$"Nome: {txtNome.Text}\n" +
$"Cognome: {txtCognome.Text}\n" +
$"Email: {txtEmail.Text}";
MessageBox.Show(messaggio,
"✅ Invio Completato",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
// Pulisci il form dopo l'invio
PulisciForm();
}
// ═══════════════════════════════════════════════════════
// METODO HELPER: Pulisce tutti i campi
// ═══════════════════════════════════════════════════════
private void PulisciForm()
{
txtNome.Text = "";
txtCognome.Text = "";
txtEmail.Text = "";
lblMessaggio.Text = "";
btnInvia.Enabled = false;
txtNome.Focus(); // Riporta il cursore sul primo campo
}
}
}
Ora devi dire a Visual Studio che il metodo TextBox_TextChanged
deve essere chiamato quando scrivi nelle TextBox. Segui questa procedura:
-
Per txtNome:
- Clicca su
txtNomenel Designer - Premi F4 per aprire la finestra Proprietà
- Clicca sull’icona del fulmine ⚡ (Eventi)
- Scorri fino a trovare TextChanged
- Nel menu a tendina, seleziona TextBox_TextChanged
- Clicca su
-
Per txtCognome:
- Ripeti la stessa procedura
- Seleziona lo stesso metodo: TextBox_TextChanged
-
Per txtEmail:
- Ripeti la stessa procedura
- Seleziona lo stesso metodo: TextBox_TextChanged
Quando scrivi in una qualsiasi di esse, il metodo
TextBox_TextChangedverrà chiamato automaticamente, e
sender conterrà il riferimentoalla TextBox specifica che ha generato l’evento.
Dopo aver collegato gli eventi, apri il file Form1.Designer.cs
(espandi Form1.cs in Solution Explorer). Dovresti vedere qualcosa del genere:
// Collegamento eventi generato da Visual Studio this.txtNome.TextChanged += new System.EventHandler(this.TextBox_TextChanged); this.txtCognome.TextChanged += new System.EventHandler(this.TextBox_TextChanged); this.txtEmail.TextChanged += new System.EventHandler(this.TextBox_TextChanged);
✅ Se vedi questo, gli eventi sono collegati correttamente!
- Viene chiamato
TextBox_TextChanged sendercontiene il riferimento atxtNome- Casting:
TextBox textBoxCorrente = (TextBox)sender; textBoxCorrente.Name= “txtNome”- lblMessaggio mostra: “✏️ Stai scrivendo in: txtNome”
- Chiama
VerificaFormCompleto(): - nomeValido = true ✅ (Mario ha 5 caratteri)
- cognomeValido = false ❌ (vuoto)
- emailValida = false ❌ (vuoto)
- Risultato: false
btnInvia.Enabled = false;(pulsante disabilitato)- lblMessaggio mostra: “❌ Compila tutti i campi correttamente” (rosso)
- Viene chiamato
TextBox_TextChanged sendercontiene il riferimento atxtCognome- Casting:
textBoxCorrenteora punta a txtCognome textBoxCorrente.Name= “txtCognome”- lblMessaggio mostra: “✏️ Stai scrivendo in: txtCognome”
- Chiama
VerificaFormCompleto(): - nomeValido = true ✅
- cognomeValido = true ✅ (Rossi ha 5 caratteri)
- emailValida = false ❌ (ancora vuoto)
- Risultato: false
btnInvia.Enabled = false;(ancora disabilitato)- lblMessaggio: “❌ Compila tutti i campi correttamente” (rosso)
- Viene chiamato
TextBox_TextChanged sendercontiene il riferimento atxtEmail- Casting:
textBoxCorrenteora punta a txtEmail textBoxCorrente.Name= “txtEmail”- lblMessaggio mostra: “✏️ Stai scrivendo in: txtEmail”
- Chiama
VerificaFormCompleto(): - nomeValido = true ✅
- cognomeValido = true ✅
- emailValida = true ✅ (contiene @ e .)
- Risultato: TRUE! 🎉
btnInvia.Enabled = true;⚡ Pulsante si abilita!- lblMessaggio mostra: “✅ Puoi inviare il form!” (verde)
- Viene chiamato
btnInvia_Click - MessageBox mostra i dati inseriti
- Chiama
PulisciForm(): - Tutti i campi tornano vuoti
- btnInvia torna disabilitato
- Il cursore torna su txtNome
📚 Concetti Chiave dell’Esercizio 1
null (non esiste) o vuota (“”). Fondamentale per validare campi obbligatori.
// Esempi:
string.IsNullOrEmpty("") // true (stringa vuota)
string.IsNullOrEmpty("Mario") // false (ha contenuto)
string.IsNullOrEmpty(null) // true (non esiste)
// Uso tipico:
if (string.IsNullOrEmpty(txtNome.Text))
{
MessageBox.Show("Il nome è obbligatorio!");
}
// Esempi:
" Mario ".Trim() // "Mario"
" ".Trim() // "" (stringa vuota)
"Mario Rossi".Trim() // "Mario Rossi" (spazi interni rimangono)
// Uso con validazione:
string nome = txtNome.Text.Trim();
if (nome.Length >= 2) // Ignora spazi iniziali/finali
{
// Nome valido
}
// Esempi:
"mario@gmail.com".Contains("@") // true
"ciao mondo".Contains("mondo") // true
"TESTO".Contains("test") // false (case-sensitive!)
// Validazione email semplice:
bool emailValida = txtEmail.Text.Contains("@") &&
txtEmail.Text.Contains(".");
true solo se TUTTE le condizioni sono vere. Usato per combinare validazioni multiple.
// Tabella di verità:
true && true // true
true && false // false
false && false // false
// Uso pratico - tutte devono essere vere:
bool formValido = !string.IsNullOrEmpty(txtNome.Text) &&
!string.IsNullOrEmpty(txtCognome.Text) &&
txtEmail.Text.Contains("@");
// formValido è true SOLO se Nome OK E Cognome OK E Email OK
// Esempi:
txtNome.Focus(); // Cursore va su txtNome
txtEmail.Focus(); // Cursore va su txtEmail
// Uso dopo la pulizia del form:
private void PulisciForm()
{
txtNome.Text = "";
txtCognome.Text = "";
txtEmail.Text = "";
txtNome.Focus(); // Riporta il cursore sul primo campo
}
🧮 Esercizio 2: Calcolatrice IMC con Feedback Visivo Avanzato
▶ Obiettivo
Creare una calcolatrice dell’Indice di Massa Corporea (IMC) che calcola automaticamente
il risultato mentre l’utente digita e cambia colore e messaggio in base
alla categoria di peso.
📖 Cos’è l’IMC (Indice di Massa Corporea)?
L’IMC è un indicatore numerico che valuta se il tuo peso è proporzionato alla tua altezza.
Si calcola con questa formula matematica:
- Peso: 70 kg
- Altezza: 1.75 m
- Calcolo: 70 / (1.75 × 1.75) = 70 / 3.0625 = 22.86
- Categoria: Normopeso ✅ (18.5 – 24.9)
- IMC < 18.5: Sottopeso
- IMC 18.5 – 24.9: Normopeso (ideale) ✅
- IMC 25.0 – 29.9: Sovrappeso
- IMC ≥ 30.0: Obesità
| Tipo | Name | Text | Proprietà Speciali |
|---|---|---|---|
| Label | lblPeso | “Peso (kg):” | – |
| TextBox | txtPeso |
vuoto | – |
| Label | lblAltezza | “Altezza (m):” | – |
| TextBox | txtAltezza |
vuoto | – |
| Label | lblRisultato |
“IMC: –“ | Font: 16pt, Bold |
| Label | lblCategoria |
vuoto | Font: 12pt |
using System;
using System.Drawing;
using System.Windows.Forms;
namespace CalcolatriceIMC
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// METODO UNICO: Calcola IMC quando scrivi in txtPeso o txtAltezza
// ═══════════════════════════════════════════════════════
private void TextBox_TextChanged(object sender, EventArgs e)
{
// 🎯 sender non serve qui perché controlliamo entrambi i campi
// Ma lo usiamo comunque per mostrare il concetto
TextBox txtCorrente = (TextBox)sender;
// Calcola solo se ENTRAMBI i campi contengono valori numerici validi
if (ValidaNumeri())
{
CalcolaEMostraIMC();
}
else
{
// Se i dati non sono validi, resetta la visualizzazione
ResetVisualizzazione();
}
}
// ═══════════════════════════════════════════════════════
// METODO: Valida che entrambi i campi contengano numeri
// ═══════════════════════════════════════════════════════
private bool ValidaNumeri()
{
// TryParse prova a convertire, restituisce true se riesce
// Valida peso: deve essere un numero > 0
bool pesoValido = double.TryParse(txtPeso.Text, out double peso) &&
peso > 0 &&
peso <= 300; // Limite ragionevole
// Valida altezza: deve essere un numero > 0 e < 3 metri
bool altezzaValida = double.TryParse(txtAltezza.Text, out double altezza) &&
altezza > 0 &&
altezza < 3.0;
// Restituisci true solo se entrambi sono validi
return pesoValido && altezzaValida;
}
// ═══════════════════════════════════════════════════════
// METODO: Calcola l'IMC e mostra il risultato con colori
// ═══════════════════════════════════════════════════════
private void CalcolaEMostraIMC()
{
// Converti i testi in numeri (sappiamo già che sono validi)
double peso = Convert.ToDouble(txtPeso.Text);
double altezza = Convert.ToDouble(txtAltezza.Text);
// 📐 FORMULA IMC: peso / (altezza × altezza)
double imc = peso / (altezza * altezza);
// Mostra il risultato arrotondato a 2 decimali
lblRisultato.Text = $"IMC: {imc:F2}";
// 🎨 Determina categoria e colore in base al valore IMC
if (imc < 18.5)
{
// Sottopeso
lblCategoria.Text = "📉 Sottopeso";
lblCategoria.ForeColor = Color.Blue;
lblRisultato.ForeColor = Color.Blue;
}
else if (imc >= 18.5 && imc < 25)
{
// Normopeso (ideale)
lblCategoria.Text = "✅ Normopeso - Peso Ideale!";
lblCategoria.ForeColor = Color.Green;
lblRisultato.ForeColor = Color.Green;
}
else if (imc >= 25 && imc < 30)
{
// Sovrappeso
lblCategoria.Text = "⚠️ Sovrappeso";
lblCategoria.ForeColor = Color.Orange;
lblRisultato.ForeColor = Color.Orange;
}
else
{
// Obesità (IMC >= 30)
lblCategoria.Text = "❌ Obesità";
lblCategoria.ForeColor = Color.Red;
lblRisultato.ForeColor = Color.Red;
}
}
// ═══════════════════════════════════════════════════════
// METODO: Resetta la visualizzazione
// ═══════════════════════════════════════════════════════
private void ResetVisualizzazione()
{
lblRisultato.Text = "IMC: --";
lblRisultato.ForeColor = Color.Black;
lblCategoria.Text = "Inserisci peso e altezza validi";
lblCategoria.ForeColor = Color.Gray;
}
}
}
Per txtPeso:
- Seleziona
txtPesonel Designer - F4 → Fulmine ⚡ → TextChanged
- Seleziona
TextBox_TextChanged
Per txtAltezza:
- Seleziona
txtAltezzanel Designer - F4 → Fulmine ⚡ → TextChanged
- Seleziona lo stesso metodo:
TextBox_TextChanged
Ogni volta che scrivi in una di esse, il calcolo dell’IMC viene eseguito automaticamente!
- Utente digita “70” in
txtPeso - Viene chiamato
TextBox_TextChanged ValidaNumeri()controlla:- pesoValido = true ✅ (70 è valido)
- altezzaValida = false ❌ (campo vuoto)
- Risultato: false
- Chiama
ResetVisualizzazione() - Mostra: “IMC: –” / “Inserisci peso e altezza validi” (grigio)
- Utente digita “1.75” in
txtAltezza - Viene chiamato
TextBox_TextChanged ValidaNumeri()controlla:- pesoValido = true ✅
- altezzaValida = true ✅
- Risultato: TRUE! 🎉
- Chiama
CalcolaEMostraIMC() - Calcola: 70 / (1.75 × 1.75) = 22.86
- 22.86 è tra 18.5 e 25 → Normopeso
- Mostra: “IMC: 22.86” (VERDE)
- Mostra: “✅ Normopeso – Peso Ideale!” (VERDE)
- Utente cambia peso da “70” a “95”
- Viene chiamato
TextBox_TextChanged ValidaNumeri()→ true ✅- Ricalcola automaticamente: 95 / (1.75 × 1.75) = 31.02
- 31.02 è ≥ 30 → Obesità
- Mostra: “IMC: 31.02” (ROSSO)
- Mostra: “❌ Obesità” (ROSSO)
- Peso rimane “95”, altezza cambia da “1.75” a “1.85”
- Ricalcola: 95 / (1.85 × 1.85) = 27.76
- 27.76 è tra 25 e 30 → Sovrappeso
- Mostra: “IMC: 27.76” (ARANCIONE)
- Mostra: “⚠️ Sovrappeso” (ARANCIONE)
📚 Concetti Chiave dell’Esercizio 2
double). Restituisce true se la conversione riesce, false altrimenti. MOLTO più sicuro di Convert.ToDouble() perché non genera errori.
// Sintassi:
double.TryParse(stringa, out variabileDestinazione)
// Esempi:
bool ok1 = double.TryParse("12.5", out double numero1);
// ok1 = true, numero1 = 12.5
bool ok2 = double.TryParse("abc", out double numero2);
// ok2 = false, numero2 = 0 (valore di default)
// Uso pratico con validazione:
if (double.TryParse(txtPeso.Text, out double peso) && peso > 0)
{
// Conversione riuscita E peso positivo
Console.WriteLine($"Peso valido: {peso}");
}
else
{
// Conversione fallita O peso <= 0
MessageBox.Show("Inserisci un peso valido!");
}
Convert.ToDouble("abc")→ 💥 ERRORE (eccezione)double.TryParse("abc", out _)→ ✅ false (nessun errore)- TryParse è ideale per validazione input utente
:F2 = 2 decimali.
// Esempi di formattazione:
double numero = 22.8571428;
// Vari formati:
numero.ToString() // "22.8571428" (tutti i decimali)
numero.ToString("F2") // "22.86" (2 decimali, arrotondato)
numero.ToString("F0") // "23" (nessun decimale)
numero.ToString("F4") // "22.8571" (4 decimali)
// Con string interpolation:
string risultato = $"IMC: {numero:F2}"; // "IMC: 22.86"
// Altri formati utili:
numero.ToString("N2") // "22,86" (separatore migliaia)
numero.ToString("C2") // "€ 22,86" (valuta con 2 decimali)
ForeColor) o dello sfondo (BackColor) di un controllo per dare feedback visivo all'utente.
// Colori predefiniti: label.ForeColor = Color.Red; label.ForeColor = Color.Green; label.ForeColor = Color.Blue; label.ForeColor = Color.Orange; label.ForeColor = Color.Gray; label.ForeColor = Color.Black; // Colore personalizzato RGB (rosso, verde, blu) da 0 a 255: label.ForeColor = Color.FromArgb(255, 100, 50); // Arancione custom // Colore di sfondo: textBox.BackColor = Color.Yellow; textBox.BackColor = Color.LightGray; // Combinazione testo + sfondo: label.ForeColor = Color.White; label.BackColor = Color.DarkGreen; // Testo bianco su sfondo verde scuro
- ✅ Verde: Tutto OK, valore ideale
- ⚠️ Arancione: Attenzione, valore border-line
- ❌ Rosso: Errore, valore critico
- ℹ️ Blu: Informazione neutra
- ⚪ Grigio: Disabilitato o non applicabile
if.
// Operatori di confronto:
imc < 18.5 // minore di
imc <= 18.5 // minore o uguale a
imc > 30 // maggiore di
imc >= 30 // maggiore o uguale a
imc == 25 // uguale a
imc != 25 // diverso da
// Operatori logici:
imc >= 18.5 && imc < 25 // AND: entrambe devono essere vere
imc < 18.5 || imc >= 30 // OR: almeno una deve essere vera
!(imc >= 25) // NOT: inverte il valore (true diventa false)
// Esempi pratici nell'IMC:
if (imc >= 18.5 && imc < 25)
{
// Normopeso: imc è maggiore o uguale a 18.5 E minore di 25
}
if (peso > 0 && altezza > 0)
{
// Entrambi i valori sono positivi
}
🎯 Esercizio 3: Gestire Più Eventi sullo Stesso Controllo
🤔 Nuovo Concetto: Un Controllo, Più Eventi
Finora abbiamo visto come UN evento (es: TextChanged) può essere gestito da PIÙ controlli (più TextBox).
Ora facciamo il contrario: UN controllo può generare DIVERSI TIPI di eventi che vogliamo gestire contemporaneamente!
| Evento | Quando Si Attiva | Uso Tipico |
|---|---|---|
| TextChanged | Quando il testo cambia | Validazione in tempo reale |
| Enter | Quando il controllo riceve il focus (ci clicchi dentro o arrivi con Tab) | Evidenziare campo attivo, mostrare suggerimenti |
| Leave | Quando il controllo perde il focus (esci con Tab o click altrove) | Validazione finale, formattazione dati |
| KeyPress | Quando premi un tasto mentre la TextBox ha focus | Bloccare caratteri non voluti (solo numeri, solo lettere) |
- Enter: Cambia colore sfondo per evidenziare il campo attivo
- Leave: Valida i dati quando l'utente finisce di scrivere
- KeyPress: Blocca caratteri non validi (es: lettere in un campo numerico)
- TextChanged: Feedback in tempo reale durante la digitazione
▶ Obiettivo
Creare TextBox intelligenti che:
- Cambiano colore quando ci clicchi dentro (Enter)
- Tornano al colore normale quando esci (Leave)
- Validano i dati quando esci dal campo (Leave)
- Bloccano caratteri non validi mentre scrivi (KeyPress)
| Tipo | Name | Text/Descrizione |
|---|---|---|
| Label | lblNome | "Nome:" |
| TextBox | txtNome |
Campo testo - validazione min 2 caratteri |
| Label | lblEta | "Età:" |
| TextBox | txtEta |
Solo numeri - validazione 0-120 |
| Label | lblEmail | "Email:" |
| TextBox | txtEmail |
Validazione @ e . |
| Label | lblMessaggio |
Feedback eventi (vuota inizialmente) |
using System;
using System.Drawing;
using System.Windows.Forms;
namespace EventiMultipli
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// EVENTO ENTER: Quando il cursore ENTRA nella TextBox
// ═══════════════════════════════════════════════════════
private void TextBox_Enter(object sender, EventArgs e)
{
// Converti sender in TextBox
TextBox txt = (TextBox)sender;
// 🎨 Cambia il colore di sfondo in giallo chiaro
txt.BackColor = Color.LightYellow;
// 💬 Mostra messaggio di feedback
lblMessaggio.Text = $"✏️ Stai scrivendo in: {txt.Name}";
lblMessaggio.ForeColor = Color.Blue;
}
// ═══════════════════════════════════════════════════════
// EVENTO LEAVE: Quando il cursore ESCE dalla TextBox
// ═══════════════════════════════════════════════════════
private void TextBox_Leave(object sender, EventArgs e)
{
// Converti sender in TextBox
TextBox txt = (TextBox)sender;
// 🎨 Riporta il colore di sfondo a bianco
txt.BackColor = Color.White;
// ✅ VALIDAZIONE in base al campo specifico
bool valido = true;
string messaggioErrore = "";
if (txt == txtNome)
{
// Valida NOME: min 2 caratteri
if (string.IsNullOrEmpty(txt.Text) || txt.Text.Trim().Length < 2)
{
valido = false;
messaggioErrore = "Il nome deve avere almeno 2 caratteri!";
}
}
else if (txt == txtEta)
{
// Valida ETÀ: deve essere numero tra 0 e 120
if (!int.TryParse(txt.Text, out int eta) || eta < 0 || eta > 120)
{
valido = false;
messaggioErrore = "Inserisci un'età valida (0-120)!";
}
}
else if (txt == txtEmail)
{
// Valida EMAIL: deve contenere @ e .
if (!txt.Text.Contains("@") || !txt.Text.Contains("."))
{
valido = false;
messaggioErrore = "Inserisci un'email valida (deve contenere @ e .)!";
}
}
// Mostra errore se non valido
if (!valido)
{
MessageBox.Show(messaggioErrore,
"⚠️ Errore di Validazione",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
// Rimetti il focus sulla TextBox per correggere l'errore
txt.Focus();
txt.SelectAll(); // Seleziona tutto il testo per sovrascrivere facilmente
lblMessaggio.Text = "❌ Correggi il campo evidenziato";
lblMessaggio.ForeColor = Color.Red;
}
else
{
lblMessaggio.Text = "✅ Campo validato correttamente";
lblMessaggio.ForeColor = Color.Green;
}
}
// ═══════════════════════════════════════════════════════
// EVENTO KEYPRESS: Quando premi un TASTO (solo per txtEta)
// ═══════════════════════════════════════════════════════
private void txtEta_KeyPress(object sender, KeyPressEventArgs e)
{
// 🔒 Permetti SOLO numeri e backspace (tasto cancella) in txtEta
// char.IsDigit() verifica se è una cifra (0-9)
// Keys.Back è il codice del tasto backspace
bool isNumero = char.IsDigit(e.KeyChar);
bool isBackspace = e.KeyChar == (char)Keys.Back;
if (!isNumero && !isBackspace)
{
// ❌ Blocca il tasto (non lo fa inserire)
e.Handled = true;
// Mostra feedback
lblMessaggio.Text = "⚠️ Solo numeri in questo campo!";
lblMessaggio.ForeColor = Color.Red;
}
}
}
}
- Seleziona
txtNomenel Designer - Premi F4 → Clicca sul fulmine ⚡
- Trova Enter → seleziona
TextBox_Enter - Trova Leave → seleziona
TextBox_Leave
📝 Collegamento per txtEta:
- Seleziona
txtEtanel Designer - F4 → Fulmine ⚡
- Trova Enter → seleziona
TextBox_Enter - Trova Leave → seleziona
TextBox_Leave - Trova KeyPress → seleziona
txtEta_KeyPress⚠️ (metodo specifico!)
📝 Collegamento per txtEmail:
- Seleziona
txtEmailnel Designer - F4 → Fulmine ⚡
- Trova Enter → seleziona
TextBox_Enter - Trova Leave → seleziona
TextBox_Leave
| TextBox | Enter | Leave | KeyPress |
|---|---|---|---|
txtNome |
TextBox_Enter | TextBox_Leave | - |
txtEta |
TextBox_Enter | TextBox_Leave | txtEta_KeyPress |
txtEmail |
TextBox_Enter | TextBox_Leave | - |
- Evento: Enter
- Viene chiamato
TextBox_Enter sender= txtNome- Sfondo diventa giallo chiaro
- lblMessaggio mostra: "✏️ Stai scrivendo in: txtNome" (blu)
- Evento: Leave
- Viene chiamato
TextBox_Leave sender= txtNome- Sfondo torna bianco
- Validazione:
txt == txtNome→ true - "M".Trim().Length = 1 < 2 → ❌ Non valido!
- MessageBox: "Il nome deve avere almeno 2 caratteri!"
txt.Focus()→ Il cursore torna su txtNometxt.SelectAll()→ "M" viene selezionato (pronto per sovrascrivere)- lblMessaggio: "❌ Correggi il campo evidenziato" (rosso)
- Evento: Leave
- Sfondo torna bianco
- Validazione: "Mario".Trim().Length = 5 ≥ 2 → ✅ Valido!
- lblMessaggio: "✅ Campo validato correttamente" (verde)
- Il cursore passa automaticamente a txtEta (prossimo controllo in ordine)
- Evento: Enter
- Sfondo diventa giallo chiaro
- lblMessaggio: "✏️ Stai scrivendo in: txtEta" (blu)
- Preme "a":
- Evento: KeyPress
txtEta_KeyPressviene chiamatochar.IsDigit('a')= false (non è un numero)e.KeyChar == Keys.Back= false (non è backspace)e.Handled = true;→ ❌ Blocca il tasto!- "a" NON viene inserito nella TextBox
- lblMessaggio: "⚠️ Solo numeri in questo campo!" (rosso)
- Stesso comportamento per "b" e "c" → bloccati
- Risultato: txtEta rimane vuota
- Preme "2":
- Evento: KeyPress
char.IsDigit('2')= true ✅e.Handled = false;(default) → Tasto permesso- "2" viene inserito in txtEta
- Preme "5": stesso processo → "5" inserito
- txtEta ora contiene: "25"
- Evento: Leave
- Sfondo torna bianco
- Validazione:
int.TryParse("25", out int eta)= true, eta = 25 - 25 ≥ 0 && 25 ≤ 120 → ✅ Valido!
- lblMessaggio: "✅ Campo validato correttamente" (verde)
- Il cursore passa a txtEmail
📚 Nuovi Concetti - Eventi e Validazione
private void TextBox_Enter(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
// Evidenzia il campo attivo
txt.BackColor = Color.LightYellow;
// Mostra aiuto contestuale
lblAiuto.Text = "Inserisci il tuo nome completo";
}
private void TextBox_Leave(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
// Rimuovi evidenziazione
txt.BackColor = Color.White;
// Valida i dati
if (string.IsNullOrEmpty(txt.Text))
{
MessageBox.Show("Campo obbligatorio!");
txt.Focus(); // Rimetti il cursore qui
}
}
private void TextBox_KeyPress(object sender, KeyPressEventArgs e)
{
// Esempio 1: Solo numeri
if (!char.IsDigit(e.KeyChar) && e.KeyChar != (char)Keys.Back)
{
e.Handled = true; // Blocca il tasto
}
// Esempio 2: Solo lettere
if (!char.IsLetter(e.KeyChar) && e.KeyChar != (char)Keys.Back)
{
e.Handled = true;
}
// Esempio 3: Solo numeri, punto, virgola
if (!char.IsDigit(e.KeyChar) &&
e.KeyChar != '.' &&
e.KeyChar != ',' &&
e.KeyChar != (char)Keys.Back)
{
e.Handled = true;
}
}
char per verificare il tipo di carattere.
// char.IsDigit() - verifica se è una cifra (0-9)
char.IsDigit('5') // true
char.IsDigit('a') // false
// char.IsLetter() - verifica se è una lettera (a-z, A-Z)
char.IsLetter('M') // true
char.IsLetter('5') // false
// char.IsControl() - verifica se è un carattere di controllo
char.IsControl('\t') // true (tab)
char.IsControl('\b') // true (backspace)
// char.IsWhiteSpace() - verifica se è uno spazio
char.IsWhiteSpace(' ') // true
char.IsWhiteSpace('\t') // true (tab)
true, il tasto premuto viene bloccato e non inserito nel controllo.
private void txtNumerico_KeyPress(object sender, KeyPressEventArgs e)
{
// Se NON è un numero E NON è backspace
if (!char.IsDigit(e.KeyChar) && e.KeyChar != (char)Keys.Back)
{
e.Handled = true; // BLOCCA il tasto
// Il carattere NON verrà inserito nella TextBox
// È come se l'utente non avesse premuto nulla
}
}
// .Focus() - sposta il cursore su un controllo
txtNome.Focus(); // Il cursore va in txtNome
// .SelectAll() - seleziona tutto il testo
txtNome.SelectAll(); // Tutto il testo viene evidenziato
// Uso combinato per correggere errori:
private void TextBox_Leave(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
if (string.IsNullOrEmpty(txt.Text))
{
MessageBox.Show("Campo obbligatorio!");
txt.Focus(); // Torna sul campo
txt.SelectAll(); // Seleziona tutto per sovrascrivere
}
}
// int.TryParse() - converte in numero intero
int.TryParse("25", out int numero) // true, numero = 25
int.TryParse("25.5", out int numero) // false (ha decimali)
int.TryParse("abc", out int numero) // false
// double.TryParse() - converte in numero decimale
double.TryParse("25.5", out double num) // true, num = 25.5
double.TryParse("25", out double num) // true, num = 25.0
double.TryParse("abc", out double num) // false
// Scelta del tipo giusto:
// - Età, quantità, contatori → int.TryParse()
// - Peso, altezza, prezzi, percentuali → double.TryParse()
💎 Best Practices: Buone Abitudini di Programmazione
✅ DA FARE (Good Practices)
// ✅ BUONO - si capisce subito cosa fa private void TextBox_TextChanged(object sender, EventArgs e) private void ValidaCampoEmail() private void CalcolaEMostraIMC() // ❌ CATTIVO - nomi vaghi private void Metodo1(object sender, EventArgs e) private void Func() private void DoStuff()
// ✅ BUONO - valida prima di usare
if (double.TryParse(txtPeso.Text, out double peso) && peso > 0)
{
// Usa "peso" sapendo che è valido
}
// ❌ CATTIVO - assume che l'input sia corretto
double peso = Convert.ToDouble(txtPeso.Text); // 💥 Può crashare!
// ✅ BUONO - sicuro, non va mai in errore
if (int.TryParse(txtEta.Text, out int eta))
{
// Conversione riuscita
}
// ❌ CATTIVO - può generare eccezione
int eta = Convert.ToInt32(txtEta.Text); // 💥 Se non è un numero, crash!
// ✅ BUONO - l'utente capisce subito cosa succede
if (valido)
{
lblMessaggio.Text = "✅ Dati validi";
lblMessaggio.ForeColor = Color.Green;
}
else
{
lblMessaggio.Text = "❌ Errore: " + dettaglioErrore;
lblMessaggio.ForeColor = Color.Red;
}
// ❌ CATTIVO - nessun feedback
if (valido)
{
// L'utente non sa se ha funzionato o no
}
// ✅ BUONO - spiega il PERCHÉ
// Blocca caratteri non numerici, ma permette backspace per correggere
if (!char.IsDigit(e.KeyChar) && e.KeyChar != (char)Keys.Back)
{
e.Handled = true;
}
// ❌ CATTIVO - nessuna spiegazione
if (!char.IsDigit(e.KeyChar) && e.KeyChar != (char)Keys.Back)
{
e.Handled = true;
}
Il codice dice già cosa fa, i commenti devono spiegare il motivo.
// ✅ BUONO - logica separata e riutilizzabile
private void btnCalcola_Click(object sender, EventArgs e)
{
if (!ValidaInput())
return;
double risultato = CalcolaIMC();
MostraRisultato(risultato);
}
// ❌ CATTIVO - tutto in un metodo gigante
private void btnCalcola_Click(object sender, EventArgs e)
{
// 200 righe di codice tutte qui...
}
❌ DA EVITARE (Bad Practices)
Se copi-incolli lo stesso codice più volte, stai sbagliando approccio.
Usa eventi condivisi e metodi helper!
// ❌ CATTIVO - codice ripetuto 4 volte
private void txtNome_TextChanged(...) { /* validazione / }
private void txtCognome_TextChanged(...) { / stessa validazione / }
private void txtEmail_TextChanged(...) { / stessa validazione / }
private void txtTelefono_TextChanged(...) { / stessa validazione */ }
// ✅ BUONO - un solo metodo per tutti
private void TextBox_TextChanged(object sender, EventArgs e)
{
TextBox txt = (TextBox)sender;
// Validazione unica
}
// ❌ CATTIVO - assume sempre input corretto
double numero = Convert.ToDouble(txtInput.Text);
double risultato = 100 / numero; // 💥 Cosa succede se numero = 0?
// ✅ BUONO - gestisce casi anomali
if (double.TryParse(txtInput.Text, out double numero) && numero != 0)
{
double risultato = 100 / numero;
}
else
{
MessageBox.Show("Inserisci un numero valido diverso da zero");
}
Non esagerare! Usa solo gli eventi necessari.
Avere 5-6 eventi diversi su una TextBox rende il codice confuso.
// ❌ ESAGERATO - troppi eventi txtNome.TextChanged += ... txtNome.Enter += ... txtNome.Leave += ... txtNome.KeyPress += ... txtNome.KeyDown += ... txtNome.KeyUp += ... txtNome.Click += ... // ✅ GIUSTO - solo ciò che serve txtNome.TextChanged += ... // Validazione in tempo reale txtNome.Leave += ... // Validazione finale
// ❌ CATTIVO - nomi autogenerati button1_Click textBox1_TextChanged label1.Text = ... // ✅ BUONO - nomi descrittivi btnCalcola_Click txtNome_TextChanged lblRisultato.Text = ...
🎯 Regola d'Oro della Programmazione ad Eventi
"Se stai scrivendo lo stesso codice più di due volte,
c'è un modo migliore per farlo."
Questa regola si chiama DRY (Don't Repeat Yourself).
Ogni volta che ti ritrovi a copiare codice, fermati e pensa:
"Posso usare un metodo condiviso? Un evento multiplo? Una funzione helper?"
📋 Tabella Riferimento Rapido: Eventi Comuni
| Evento | Quando Si Attiva | Uso Comune | Esempio Pratico |
|---|---|---|---|
| TextChanged | Quando il testo cambia (ogni carattere digitato) | Validazione in tempo reale, calcoli automatici | Calcolatrice IMC, contatore caratteri |
| Click | Quando clicchi il controllo | Eseguire azioni, salvare dati | Pulsante "Salva", "Calcola", "Invia" |
| Enter | Quando il controllo riceve il focus | Evidenziare campo attivo, mostrare aiuto | Cambiare colore sfondo, tooltip |
| Leave | Quando il controllo perde il focus | Validare dati inseriti, formattare | Controllo email valida, formatta data |
| KeyPress | Quando premi un tasto (con focus sul controllo) | Bloccare caratteri non voluti | Solo numeri in campo età, solo lettere in nome |
| SelectedIndexChanged | Quando cambi selezione in ListBox/ComboBox | Caricare dati correlati | Selezionare auto per modificarla (Parco Auto) |
| Load | Quando il form si carica (una sola volta all'avvio) | Inizializzare controlli, caricare dati | Popolare ComboBox carburanti all'avvio |
| FormClosing | Prima che il form si chiuda | Confermare uscita, salvare dati non salvati | "Vuoi salvare prima di uscire?" |
| DoubleClick | Quando fai doppio click | Aprire finestre dettaglio, modificare item | Doppio click su auto in ListBox per modificarla |
🏋️ Esercizi per Allenarsi
⭐ Livello Facile
- Crea 3 TextBox: txtMessaggio1, txtMessaggio2, txtMessaggio3
- Aggiungi una Label: lblTotaleCaratteri
- Quando scrivi in una qualsiasi TextBox, mostra il totale di caratteri di TUTTE e 3
- Usa UN SOLO metodo TextChanged per tutte le TextBox
txtMessaggio1.Text.Length + txtMessaggio2.Text.Length + txtMessaggio3.Text.Length
- Riprendi l'esercizio 1 (Contatore Caratteri)
- Aggiungi un Button: btnReset
- Quando clicchi il pulsante, cancella TUTTE le TextBox
- Mostra un MessageBox: "Campi azzerati!"
⭐⭐ Livello Medio
- Crea 2 TextBox: txtNumero1, txtNumero2
- Crea 4 Button: btnSomma, btnSottrazione, btnMoltiplicazione, btnDivisione
- Aggiungi Label: lblRisultato
- Il risultato si aggiorna automaticamente mentre scrivi i numeri
- Le TextBox diventano rosse se inserisci valori non numerici
- I pulsanti si disabilitano se i campi non sono validi
- Usa
double.TryParse()per validare - Usa
TextBox_TextChangedcondiviso per entrambe le TextBox - Cambia
txtNumero1.BackColorin base alla validità
- Crea TextBox: txtNome, txtCognome, txtEmail, txtPassword, txtConfermaPassword
- Validazione:
- Nome e Cognome: min 2 caratteri
- Email: deve contenere @ e .
- Password: min 6 caratteri
- Conferma Password: deve coincidere con Password
- Quando un campo è valido, mostra ✅ verde accanto
- Quando non valido, mostra ❌ rosso con motivo
- Il pulsante "Registrati" si abilita solo se TUTTO è valido
per mostrare icone e messaggi accanto a ogni campo.
⭐⭐⭐ Livello Difficile
- Step 1 - Dati Personali: Nome, Cognome, Data di Nascita
- Step 2 - Contatti: Email, Telefono
- Step 3 - Credenziali: Username, Password, Conferma Password
- Validazioni specifiche per ogni campo
- Pulsanti "Avanti" e "Indietro" per navigare tra gli step
- "Avanti" si abilita solo se lo step corrente è valido
- Feedback visivo con colori e icone ✅❌
- Barra di progresso: "Step 1 di 3", "Step 2 di 3", ecc.
prima della "Conferma Registrazione".
- 2 TextBox numeriche con validazione
- 8 operazioni: +, -, ×, ÷, x², √, %, 1/x
- Risultato si aggiorna in tempo reale
- Gestione errori: divisione per zero, radice di numero negativo
- Cronologia operazioni in una ListBox
- Pulsante "Pulisci Tutto" per reset completo
🎓 Riepilogo: Cosa Hai Imparato
✨ Competenze Acquisite
Hai capito come identificare QUALE controllo ha generato un evento usando
sender, il segreto per scrivere meno codice.
Sai trasformare sender nel tipo giusto usando casting:
(TextBox)sender, (Button)sender, ecc.
Hai imparato a condividere la logica tra controlli simili,
riducendo la duplicazione del codice del 75% o più!
Feedback in tempo reale mentre l'utente digita, con validazione
automatica e controlli che si abilitano/disabilitano intelligentemente.
Gestione combinata di Enter, Leave, KeyPress sullo stesso controllo
per creare TextBox intelligenti e user-friendly.
Codice pulito, manutenibile e professionale seguendo le buone
abitudini della programmazione (DRY, validazione, feedback visivo).
Con questa lezione hai fatto un salto di qualità enorme nella gestione degli eventi.
Non scrivi più codice ripetitivo e inefficiente: ora programmi come un professionista,
con codice DRY (Don't Repeat Yourself), riutilizzabile e facile da manutenere.
Queste tecniche sono usate quotidianamente dagli sviluppatori professionisti in tutto il mondo!
🚀 Prossimi Passi: Verso la Teoria Fondamentale
📖 Nella Prossima Lezione Imparerai:
Lezione 7 - Variabili, Tipi di Dato e Operatori (TEORIA)
- 🔢 Variabili: int, double, string, bool - cosa sono e come usarle
- 📊 Tipi di Dato: Quando usare int vs double? string vs char?
- ➕ Operatori Aritmetici: +, -, *, /, % con esempi pratici GUI
- 🔀 Operatori di Confronto: ==, !=, <, >, <=, >= nelle validazioni
- 🔗 Operatori Logici: &&, ||, ! per condizioni complesse
- 💡 Casting e Conversioni: Convert vs Parse vs TryParse - la guida definitiva
- 🎯 Esercizi Pratici: Calcolatrici, convertitori, validatori
🎯 Finora hai usato variabili e operatori "per intuito". Nella prossima lezione
capirai VERAMENTE cosa succede dietro le quinte: come funziona la memoria,
perché usiamo tipi diversi, come evitare errori comuni. Sarà la base teorica
che ti renderà un programmatore consapevole!
Hai già praticato con TextBox, Button, eventi, oggetti (Automobile), liste.
Ora è il momento perfetto per consolidare le basi teoriche.
Capirai PERCHÉ hai fatto certe scelte fino ad ora e sarai pronto per progetti ancora più complessi!
- Completa gli Esercizi 1 e 2 di questa lezione (Form Contatto e Calcolatrice IMC)
- Prova l'Esercizio 3 (Eventi Multipli) per familiarizzare con Enter/Leave/KeyPress
- Riprendi il Parco Auto (Lezione 5) e applica la validazione con eventi multipli
- Sfida: Migliora il Form Contatto aggiungendo un campo Telefono che accetta solo numeri
Lezione 6 - Gestione Avanzata di Eventi Multipli in C#
Corso C# Completo con Interfaccia Grafica - Da Zero a Esperto
© 2025 Academy PC - Tutti i diritti riservati