Scrivi meno codice, ottieni piΓΉ funzionalitΓ : il segreto del parametro sender.
Il Salto: Da Oggetti a Eventi Intelligenti
Nel Progetto Parco Auto 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...
β Il Problema della Duplicazione del Codice
Parco Auto - Codice Ripetitivo (Da Evitare)
// 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!
β οΈ Problemi di questo Approccio:
- π 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
β La Soluzione: UN Metodo per TUTTE le TextBox
Approccio Professionale con sender
// 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!
β Vantaggi Immediati:
- βοΈ 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)
π Cosa Imparerai in Questa Lezione
- β 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
π Collegamento con le Lezioni Precedenti
Primi esercizi (eventi base): Hai usato
btnCalcola_Clickper un solo pulsante Parco Auto: Hai gestito eventi separati per ogni TextBox Questa lezione: 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.
π¦ object sender
sender Γ¨ un riferimento all'oggetto (controllo) che ha generato l'evento.
In pratica, ti dice CHI ha chiamato questo metodo.
π Analogia della Vita Reale:
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
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".
π‘ Nota: In questa lezione ci concentreremo principalmente su sender,
che Γ¨ il piΓΉ importante per gestire eventi multipli. Vedremo EventArgs negli esempi avanzati.
Esempio Pratico: Capire sender
Esperimento con 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
}
Esperimento da Provare Subito!
- 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)?
π¦ Analogia del Pacco Generico:
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
Sintassi del 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
(TextBox)sender
Converte sender in una TextBox. Usa questo quando gestisci eventi di TextBox come TextChanged, Enter, Leave.
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;
}
(Button)sender
Converte sender in un Button. Usa questo quando gestisci Click di piΓΉ pulsanti con un solo metodo.
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;
}
(ComboBox)sender / (ListBox)sender
Converte sender in ComboBox o ListBox. Utile per gestire SelectedIndexChanged di piΓΉ controlli.
private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cmb = (ComboBox)sender;
// Ora puoi usare:
string selezione = cmb.SelectedItem.ToString();
int indice = cmb.SelectedIndex;
}
β οΈ Cosa Succede se Sbagli il Casting?
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.
π― Cosa Imparerai:
- β
Usare
senderper gestire piΓΉ TextBox con un metodo - β Validazione in tempo reale (feedback istantaneo)
- β Abilitare/disabilitare controlli dinamicamente
- β Feedback visivo con colori e messaggi
- Crea l'Interfaccia Grafica
Controlli Necessari:
| 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 |
- Il Codice Completo Spiegato
Form1.cs - Form Contatto
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
}
}
}
- β‘ IMPORTANTISSIMO: Come Collegare l'Evento
Ora devi dire a Visual Studio che il metodo TextBox_TextChanged
deve essere chiamato quando scrivi nelle TextBox. Segui questa procedura:
π Procedura Passo-Passo:
- Per txtNome:
- Clicca su
txtNomenel Designer - Premi
F4per 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
β¨ Risultato: Tutte e 3 le TextBox useranno lo STESSO metodo!
Quando scrivi in una qualsiasi di esse, il metodo TextBox_TextChanged
verrΓ chiamato automaticamente, e sender conterrΓ il riferimento
alla TextBox specifica che ha generato l'evento.
π Verifica Visiva nel Codice:
Dopo aver collegato gli eventi, apri il file Form1.Designer.cs
(espandi Form1.cs in Solution Explorer). Dovresti vedere qualcosa del genere:
Form1.Designer.cs (generato automaticamente)
// 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!
- π¬ Flusso di Esecuzione: Cosa Succede Passo-Passo
π Scenario Completo:
1οΈβ£ Utente scrive "Mario" in txtNome
- Viene chiamato
TextBox_TextChangedsendercontiene 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)
2οΈβ£ Utente scrive "Rossi" in txtCognome
- Viene chiamato
TextBox_TextChangedsendercontiene il riferimento atxtCognome- Casting:
textBoxCorrenteora punta a txtCognometextBoxCorrente.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)
3οΈβ£ Utente scrive "mario@gmail.com" in txtEmail
- Viene chiamato
TextBox_TextChangedsendercontiene il riferimento atxtEmail- Casting:
textBoxCorrenteora punta a txtEmailtextBoxCorrente.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)
4οΈβ£ Utente clicca "Invia"
- 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
string.IsNullOrEmpty()
Verifica se una stringa Γ¨ 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!");
}
.Trim()
Rimuove spazi bianchi all'inizio e alla fine di una stringa. Utile per evitare che l'utente "inganni" la validazione con solo spazi.
// 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
}
.Contains()
Verifica se una stringa contiene un'altra stringa o carattere. Perfetto per validazioni semplici come email.
// 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(".");
Operatore && (AND logico)
Restituisce 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
.Focus()
Sposta il cursore su un controllo specifico. Utile per guidare l'utente o riportarlo a un campo dopo la pulizia.
// 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:
IMC = Peso (kg) / (Altezza (m) Γ Altezza (m))
π‘ Esempio Pratico:
- Peso: 70 kg
- Altezza: 1.75 m
- Calcolo: 70 / (1.75 Γ 1.75) = 70 / 3.0625 = 22.86
- Categoria: Normopeso β (18.5 - 24.9)
π Categorie IMC (OMS):
- IMC < 18.5: Sottopeso
- IMC 18.5 - 24.9: Normopeso (ideale) β
- IMC 25.0 - 29.9: Sovrappeso
- IMC β₯ 30.0: ObesitΓ
- Crea l'Interfaccia
| 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 |
- Il Codice Completo
CalcolatriceIMC.cs
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;
}
}
}
- Collegamento Eventi
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
β Risultato: Entrambe le TextBox condividono lo stesso metodo. Ogni volta che scrivi in una di esse, il calcolo dell'IMC viene eseguito automaticamente!
- π¨ Cosa Succede Visivamente: Scenari d'Uso
π Scenario 1: Inserimento Peso
Utente digita "70" in
txtPesoViene 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)
π Scenario 2: Inserimento Altezza
Utente digita "1.75" in
txtAltezzaViene 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)
π Scenario 3: Modifica Peso (ObesitΓ )
- Utente cambia peso da "70" a "95"
- Viene chiamato
TextBox_TextChangedValidaNumeri()β true β- Ricalcola automaticamente: 95 / (1.75 Γ 1.75) = 31.02
- 31.02 Γ¨ β₯ 30 β ObesitΓ
- Mostra: "IMC: 31.02" (ROSSO)
- Mostra: "β ObesitΓ " (ROSSO)
π Scenario 4: Modifica Altezza (Sovrappeso)
- 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.TryParse()
Prova a convertire una stringa in numero decimale (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!");
}
π‘ PerchΓ© usare TryParse invece di Convert?
Convert.ToDouble("abc")β π₯ ERRORE (eccezione)double.TryParse("abc", out _)β β false (nessun errore)- TryParse Γ¨ ideale per validazione input utente
Formattazione :F2
Formatta un numero decimale con un numero fisso di cifre dopo la virgola. :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)
Color (cambiare colori dinamicamente)
Cambia il colore del testo (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
π¨ Best Practice per Feedback Visivo:
- β Verde: Tutto OK, valore ideale
- β οΈ Arancione: Attenzione, valore border-line
- β Rosso: Errore, valore critico
- βΉοΈ Blu: Informazione neutra
- βͺ Grigio: Disabilitato o non applicabile
Operatori di Confronto e Logici
Usati per confrontare valori e combinare condizioni nelle istruzioni 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!
π Eventi Disponibili su una TextBox:
| 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) |
π‘ PerchΓ© Usare PiΓΉ Eventi?
- 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)
-
Crea l'Interfaccia
| 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) |
- Il Codice Completo con Tutti gli Eventi
EventiMultipli.cs
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;
}
}
}
}
- β‘ Come Collegare gli Eventi Multipli (CRUCIALE!)
π Collegamento per txtNome:
- 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
β¨ Riepilogo Collegamenti:
| TextBox | Enter | Leave | KeyPress |
|---|---|---|---|
txtNome |
TextBox_Enter | TextBox_Leave | - |
txtEta |
TextBox_Enter | TextBox_Leave | txtEta_KeyPress |
txtEmail |
TextBox_Enter | TextBox_Leave | - |
- π¬ Sequenza Completa degli Eventi: Cosa Succede
1οΈβ£ Utente clicca su txtNome
- Evento: Enter
- Viene chiamato
TextBox_Entersender= txtNome- Sfondo diventa giallo chiaro
- lblMessaggio mostra: "βοΈ Stai scrivendo in: txtNome" (blu)
2οΈβ£ Utente scrive "M" e preme Tab
- Evento: Leave
- Viene chiamato
TextBox_Leavesender= 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)
3οΈβ£ Utente sovrascrive con "Mario" e preme Tab
- 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)
4οΈβ£ Il cursore entra in txtEta
- Evento: Enter
- Sfondo diventa giallo chiaro
- lblMessaggio: "βοΈ Stai scrivendo in: txtEta" (blu)
5οΈβ£ Utente prova a scrivere "abc" in txtEta
Preme "a":
Evento: KeyPress
txtEta_KeyPressviene chiamato
char.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
6οΈβ£ Utente scrive "25" in txtEta
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"
7οΈβ£ Utente preme Tab per uscire da txtEta
- 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
Evento Enter (riceve focus)
Si attiva quando un controllo riceve il focus (l'utente ci clicca dentro o ci arriva con Tab/Shift+Tab). Ideale per evidenziare il campo attivo o mostrare suggerimenti.
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";
}
Evento Leave (perde focus)
Si attiva quando un controllo perde il focus (l'utente esce cliccando altrove o premendo Tab). Perfetto per validare i dati inseriti e formattarli.
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
}
}
Evento KeyPress (tasto premuto)
Si attiva ogni volta che l'utente preme un tasto mentre il controllo ha focus. Permette di filtrare caratteri non voluti in tempo reale.
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.IsDigit() / char.IsLetter()
Metodi statici della classe 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)
KeyPressEventArgs.Handled
ProprietΓ che indica se l'evento Γ¨ stato "gestito". Se impostata a 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() e .SelectAll()
Metodi per controllare il focus e la selezione del testo in un controllo.
// .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() vs double.TryParse()
Due varianti di TryParse per numeri interi e decimali.
// 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)
1οΈβ£ Usa Nomi Descrittivi
// β
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()
2οΈβ£ Valida SEMPRE i Dati Utente
// β
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!
3οΈβ£ Usa TryParse invece di Convert
// β
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!
4οΈβ£ Dai Feedback Visivo Chiaro
// β
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
}
5οΈβ£ Commenta il Codice Complesso
// β
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;
}
π‘ Regola: Commenta il PERCHΓ fai qualcosa, non il COSA. Il codice dice giΓ cosa fa, i commenti devono spiegare il motivo.
6οΈβ£ Separa la Logica in Metodi
// β
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)
1οΈβ£ Codice Duplicato
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
}
2οΈβ£ Nessuna Gestione Errori
// β 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");
}
3οΈβ£ Troppi Eventi sullo Stesso Controllo
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
4οΈβ£ Nomi di Controlli Generici
// β 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
1οΈβ£ Contatore Caratteri Globale
- 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
π‘ Suggerimento: Nel metodo TextChanged, calcola
txtMessaggio1.Text.Length + txtMessaggio2.Text.Length + txtMessaggio3.Text.Length
2οΈβ£ Pulsante Reset Intelligente
- 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
3οΈβ£ Calcolatrice Semplice con Validazione
- 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
π‘ Suggerimenti:
- Usa
double.TryParse()per validare - Usa
TextBox_TextChangedcondiviso per entrambe le TextBox - Cambia
txtNumero1.BackColorin base alla validitΓ
4οΈβ£ Form Registrazione con Feedback Colorato
- 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
π‘ Suggerimento: Usa Label dedicate (lblErroreNome, lblErroreCognome, etc.) per mostrare icone e messaggi accanto a ogni campo.
Livello Difficile
5οΈβ£ Form Multi-Step con Validazione Progressiva
- 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.
π‘ Challenge Extra: Aggiungi un riepilogo finale con tutti i dati inseriti prima della "Conferma Registrazione".
6οΈβ£ Calcolatrice Scientifica Mini
- 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
π― Il Parametro sender
Hai capito come identificare QUALE controllo ha generato un evento usando
sender, il segreto per scrivere meno codice.
π Casting di Controlli
Sai trasformare sender nel tipo giusto usando casting:
(TextBox)sender, (Button)sender, ecc.
β‘ Un Metodo, PiΓΉ Controlli
Hai imparato a condividere la logica tra controlli simili, riducendo la duplicazione del codice del 75% o piΓΉ!
β Validazione Dinamica
Feedback in tempo reale mentre l'utente digita, con validazione automatica e controlli che si abilitano/disabilitano intelligentemente.
π¨ Eventi Multipli
Gestione combinata di Enter, Leave, KeyPress sullo stesso controllo per creare TextBox intelligenti e user-friendly.
π Best Practices
Codice pulito, manutenibile e professionale seguendo le buone abitudini della programmazione (DRY, validazione, feedback visivo).
π Da Principiante a Professionista
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
Nella Prossima Lezione Imparerai:
- π RadioButton e CheckBox: scelte singole e scelte multiple
- π₯οΈ Configuratore PC Gaming: prezzo che si aggiorna a ogni scelta, con un solo metodo per tanti controlli
- ποΈ Generatore Piano di Allenamento: combinare scelte, calcoli e messaggi
π― Userai subito quello che hai imparato qui: un solo gestore di eventi per tanti controlli, grazie a sender.
π Vuoi rivedere la teoria di variabili, operatori e conversioni? Γ nel percorso C# β il linguaggio, lezioni Variabili e tipi di dato e Operatori e casting.
πͺ Cosa Fare Prima della Prossima Lezione
- 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 e applica la validazione con eventi multipli
- Sfida: Migliora il Form Contatto aggiungendo un campo Telefono che accetta solo numeri
π Teoria collegata (percorso C# β il linguaggio, esempi in console): Operatori e casting.