Lezione 7 – Esercizi Pratici
🎮 Programmazione ad Eventi: Esercizi Guidati
Da semplici operazioni a validazioni avanzate: impara facendo
🎯 Il Tuo Percorso Finora
Hai completato un percorso incredibile! Vediamo cosa hai già imparato e cosa farai in questa lezione:
✅ Competenze Già Acquisite (Lezioni 1-6)
- ✅ Lezione 1: Installazione Visual Studio e primo “Hello World”
- ✅ Lezione 2: TextBox, Label, Button ed eventi base (Click)
- ✅ Lezione 3: ListBox, ComboBox, gestione liste
- ✅ Lezione 4: List<string> e operazioni CRUD
- ✅ Lezione 5: Classi personalizzate (Automobile), List<Automobile>, File I/O
- ✅ Lezione 6: Eventi multipli, parametro sender, validazione avanzata
🎯 Focus di Questa Lezione
Nella Lezione 6 hai imparato le tecniche avanzate di gestione eventi
(sender, casting, eventi multipli). Ora è tempo di consolidare queste
conoscenze con esercizi pratici progressivi che combinano:
- 🔢 Operazioni matematiche con validazione input
- ✅ Strutture di controllo (if/else, switch) applicate a interfacce grafiche
- 🎨 Feedback visivo dinamico (colori, messaggi, abilitazione controlli)
- 🔄 Conversioni di tipo sicure (TryParse vs Convert)
- 📊 Validazione complessa con più condizioni
Gli esercizi di questa lezione ti permettono di praticare intensivamente
i concetti fondamentali della programmazione (operatori, condizioni, conversioni)
attraverso interfacce grafiche. Non stai solo scrivendo codice astratto:
stai creando applicazioni reali che gli utenti possono usare!
Ogni esercizio introduce nuovi concetti teorici nel contesto pratico,
preparandoti gradualmente per le lezioni teoriche approfondite che seguiranno.
📚 Concetti Fondamentali Praticati
TextBox
Controllo per l’inserimento di testo e numeri
Label
Controllo per visualizzare testo e risultati
Button
Controllo che genera evento Click per azioni
Event Handler
Metodo eseguito quando si verifica un evento
🔢 Esercizio 1: Calcolatrice – Somma di Due Numeri
▶ Obiettivo
Creare la tua prima calcolatrice con interfaccia grafica! L’applicazione permette
di inserire due numeri, calcolare la somma e visualizzare il risultato.
Include validazione per evitare errori quando l’utente inserisce testo al posto di numeri.
🎯 Cosa Imparerai:
- ✅ Raccogliere input numerici da TextBox
- ✅ Convertire stringhe in numeri con
Convert.ToDouble() - ✅ Eseguire operazioni matematiche (somma)
- ✅ Gestire errori con
try-catch - ✅ Validare input con
string.IsNullOrEmpty() - ✅ Abilitare/disabilitare controlli dinamicamente
1
Progettazione dell’Interfaccia Grafica
Crea un nuovo Windows Forms Project:
- File → Nuovo → Progetto
- Seleziona “Applicazione Windows Forms (.NET Framework)”
- Nome:
CalcolatoriceSomma - Click su “Crea”
📐 Controlli da Aggiungere al Form:
| Tipo Controllo | Name (Nome) | Proprietà Text | Note |
|---|---|---|---|
| Label | lblNumero1 | “Primo Numero:” | Etichetta descrittiva |
| TextBox | txtNumero1 |
vuoto | Input primo numero |
| Label | lblNumero2 | “Secondo Numero:” | Etichetta descrittiva |
| TextBox | txtNumero2 |
vuoto | Input secondo numero |
| Button | btnCalcola |
“Calcola Somma” | Inizialmente disabilitato (Enabled = false) |
| Label | lblRisultato |
vuoto | Mostra risultato (Font: 14pt, Bold) |
📸 Come Dovrebbe Apparire l’Interfaccia:
Disponi i controlli in verticale: Label “Primo Numero:”, sotto la TextBox txtNumero1,
poi Label “Secondo Numero:”, sotto la TextBox txtNumero2, poi il Button btnCalcola,
e in fondo la Label lblRisultato per mostrare il risultato.
2
Gestione dell’Evento Click del Pulsante
Quando l’utente clicca sul pulsante “Calcola Somma”, dobbiamo:
- Verificare che entrambi i campi siano compilati
- Convertire i testi in numeri
- Calcolare la somma
- Mostrare il risultato
- Gestire eventuali errori
using System;
using System.Windows.Forms;
namespace CalcolatriceSomma
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// EVENTO: Click del pulsante "Calcola Somma"
// ═══════════════════════════════════════════════════════
private void btnCalcola_Click(object sender, EventArgs e)
{
// ─────────────────────────────────────────────────
// STEP 1: Validazione - Controllo campi vuoti
// ─────────────────────────────────────────────────
// string.IsNullOrEmpty() verifica se la stringa è null o vuota ("")
if (string.IsNullOrEmpty(txtNumero1.Text) ||
string.IsNullOrEmpty(txtNumero2.Text))
{
lblRisultato.Text = "⚠️ Inserisci entrambi i numeri!";
lblRisultato.ForeColor = System.Drawing.Color.Red;
return; // Esce dal metodo senza eseguire altro codice
}
// ─────────────────────────────────────────────────
// STEP 2: Conversione e Calcolo (con gestione errori)
// ─────────────────────────────────────────────────
try
{
// Converti le stringhe in numeri decimali (double)
// Convert.ToDouble() può generare eccezione se il testo non è un numero
double numero1 = Convert.ToDouble(txtNumero1.Text);
double numero2 = Convert.ToDouble(txtNumero2.Text);
// Calcola la somma
double somma = numero1 + numero2;
// ─────────────────────────────────────────────
// STEP 3: Visualizzazione Risultato
// ─────────────────────────────────────────────
// ToString() converte il numero in stringa per visualizzarlo
lblRisultato.Text = "Risultato: " + somma.ToString();
lblRisultato.ForeColor = System.Drawing.Color.Green;
}
catch (FormatException)
{
// Eccezione catturata se l'utente inserisce testo non numerico
lblRisultato.Text = "❌ Inserisci valori numerici validi!";
lblRisultato.ForeColor = System.Drawing.Color.Red;
}
catch (Exception ex)
{
// Cattura qualsiasi altra eccezione non prevista
lblRisultato.Text = "❌ Errore: " + ex.Message;
lblRisultato.ForeColor = System.Drawing.Color.Red;
}
}
}
}
🔍 Analisi Dettagliata del Codice:
1️⃣ Validazione Input:
if (string.IsNullOrEmpty(txtNumero1.Text) ||
string.IsNullOrEmpty(txtNumero2.Text))
{
// Almeno uno dei due campi è vuoto
lblRisultato.Text = "⚠️ Inserisci entrambi i numeri!";
return; // IMPORTANTE: interrompe l'esecuzione del metodo
}
L’operatore || (OR logico) restituisce true se
almeno una delle condizioni è vera. Se uno dei campi è vuoto,
mostra errore e return esce dal metodo.
2️⃣ Try-Catch per Gestione Errori:
try
{
// Codice che potrebbe generare errori
double numero1 = Convert.ToDouble(txtNumero1.Text);
}
catch (FormatException)
{
// Gestisce l'errore se Convert fallisce
lblRisultato.Text = "❌ Inserisci valori numerici!";
}
try-catch permette di “catturare” errori senza far crashare il programma.
Se Convert.ToDouble("abc") fallisce, invece di chiudere l’app,
il controllo passa al blocco catch.
3️⃣ Conversione con ToString():
double somma = 15.5; lblRisultato.Text = "Risultato: " + somma.ToString(); // Output: "Risultato: 15.5"
.Text richiede una stringa. ToString() converte
il numero in stringa per poterlo concatenare con testo.
3
Validazione Dinamica con TextChanged
Miglioriamo l’app abilitando il pulsante “Calcola” solo quando entrambi i campi
contengono numeri validi. Questo offre feedback immediato all’utente!
// ═══════════════════════════════════════════════════════
// EVENTI: TextChanged per validazione dinamica
// ═══════════════════════════════════════════════════════
private void txtNumero1_TextChanged(object sender, EventArgs e)
{
// Abilita il pulsante solo se entrambi i campi sono validi
btnCalcola.Enabled = ValidaInput();
}
private void txtNumero2_TextChanged(object sender, EventArgs e)
{
// Stesso controllo per il secondo campo
btnCalcola.Enabled = ValidaInput();
}
// ═══════════════════════════════════════════════════════
// METODO HELPER: Valida che entrambi i campi siano numeri
// ═══════════════════════════════════════════════════════
private bool ValidaInput()
{
try
{
// Prova a convertire il primo numero
if (!string.IsNullOrEmpty(txtNumero1.Text))
Convert.ToDouble(txtNumero1.Text);
// Prova a convertire il secondo numero
if (!string.IsNullOrEmpty(txtNumero2.Text))
Convert.ToDouble(txtNumero2.Text);
// Se arriviamo qui, entrambi sono numeri validi
return true;
}
catch
{
// Se Convert fallisce, ritorna false
return false;
}
}
⚡ Come Collegare gli Eventi TextChanged:
- Seleziona
txtNumero1nel Designer - Premi F4 per aprire le Proprietà
- Clicca sull’icona del fulmine ⚡ (Eventi)
- Trova TextChanged e fai doppio click
- Visual Studio crea automaticamente il metodo
txtNumero1_TextChanged - Ripeti per
txtNumero2
🎬 Flusso di Esecuzione:
- Utente apre l’app →
btnCalcola.Enabled = false(disabilitato) - Utente scrive “12” in txtNumero1 → Evento
txtNumero1_TextChanged - Chiama
ValidaInput()→ txtNumero2 è vuoto → return false btnCalcola.Enabled = false→ Pulsante ancora disabilitato- Utente scrive “8” in txtNumero2 → Evento
txtNumero2_TextChanged - Chiama
ValidaInput()→ Entrambi sono numeri validi → return true btnCalcola.Enabled = true→ ✅ Pulsante si abilita!- Utente clicca “Calcola Somma” → Evento
btnCalcola_Click - Calcola 12 + 8 = 20 → Mostra “Risultato: 20” (verde)
📚 Metodi e Concetti – Esercizio 1
Metodo statico che verifica se una stringa è null (non esiste) o vuota (""). Essenziale per validare campi obbligatori.
// Sintassi:
bool risultato = string.IsNullOrEmpty(testo);
// Esempi:
string.IsNullOrEmpty("") // true (stringa vuota)
string.IsNullOrEmpty("Mario") // false (ha contenuto)
string.IsNullOrEmpty(null) // true (non esiste)
// Uso pratico:
if (string.IsNullOrEmpty(txtNome.Text))
{
MessageBox.Show("Il campo è obbligatorio!");
}
💡 Perché Preferibile a txt.Text == “”:
txt.Text == ""→ Crash se txt.Text è nullstring.IsNullOrEmpty(txt.Text)→ Gestisce sia null che “”
Converte una stringa in numero decimale (double). Genera eccezione FormatException se la stringa non è numerica.
// Sintassi:
double numero = Convert.ToDouble(stringa);
// Esempi:
Convert.ToDouble("123.45") // 123.45
Convert.ToDouble("100") // 100.0
Convert.ToDouble("abc") // ❌ FormatException (errore!)
Convert.ToDouble("") // ❌ FormatException (errore!)
// Uso con try-catch:
try
{
double num = Convert.ToDouble(txtInput.Text);
// Usa "num" sapendo che è valido
}
catch (FormatException)
{
MessageBox.Show("Inserisci un numero valido!");
}
⚠️ Quando Usare Convert vs TryParse:
Convert.ToDouble()→ Usa con try-catch (solleva eccezioni)double.TryParse()→ Usa senza try-catch (ritorna true/false)- TryParse è generalmente preferibile per input utente
Converte qualsiasi valore nel suo equivalente rappresentazione stringa. Tutti i tipi ereditano questo metodo.
// Sintassi:
string testo = valore.ToString();
// Esempi con numeri:
int numero = 42;
numero.ToString() // "42"
double decimale = 3.14;
decimale.ToString() // "3.14"
decimale.ToString("F2") // "3.14" (2 decimali)
decimale.ToString("F0") // "3" (nessun decimale)
// Concatenazione con stringhe:
int eta = 25;
string messaggio = "Hai " + eta.ToString() + " anni";
// oppure (più moderno):
string messaggio2 = $"Hai {eta} anni"; // string interpolation
Costrutto per gestire errori (eccezioni) a runtime senza far crashare il programma.
// Struttura base:
try
{
// Codice che potrebbe generare errori
double num = Convert.ToDouble(txtInput.Text);
}
catch (FormatException ex)
{
// Gestisce errori di formato (testo non numerico)
MessageBox.Show("Inserisci un numero valido!");
}
catch (Exception ex)
{
// Cattura tutte le altre eccezioni
MessageBox.Show("Errore: " + ex.Message);
}
// Best Practice: gestisci eccezioni specifiche prima
try
{
// ...
}
catch (FormatException) // Specifica
{
// Errore formato
}
catch (OverflowException) // Specifica
{
// Numero troppo grande
}
catch (Exception ex) // Generica (ultima)
{
// Altri errori
}
Proprietà booleana che indica se un controllo è abilitato (true) o disabilitato (false). Controlli disabilitati appaiono in grigio e non rispondono a eventi.
// Abilitare/disabilitare: btnCalcola.Enabled = true; // Abilita (cliccabile) btnCalcola.Enabled = false; // Disabilita (grigio, non cliccabile) // Uso dinamico: btnCalcola.Enabled = ValidaInput(); // Abilita se ValidaInput() ritorna true // Controlli multipli: bool tuttiValidi = VerificaCampi(); btnSalva.Enabled = tuttiValidi; btnInvia.Enabled = tuttiValidi;
Restituisce true se almeno una delle condizioni è vera.
// Tabella di verità:
true || true // true
true || false // true
false || true // true
false || false // false
// Uso pratico - almeno uno deve essere vero:
if (string.IsNullOrEmpty(txtNome.Text) ||
string.IsNullOrEmpty(txtCognome.Text))
{
// Se Nome è vuoto OR Cognome è vuoto (o entrambi)
MessageBox.Show("Compila tutti i campi!");
}
// Differenza con && (AND):
// && → TUTTI devono essere veri
// || → ALMENO UNO deve essere vero
🔀 Esercizio 2: Verifica Numero Pari o Dispari
▶ Obiettivo
Creare un’applicazione che determina se un numero inserito dall’utente è pari o dispari.
Introduce l’operatore modulo (%) e l’uso di strutture condizionali (if-else)
con feedback visivo colorato.
🎯 Nuovi Concetti:
- ✅ Operatore modulo (
%) per calcolare il resto della divisione - ✅
if-elseper eseguire codice condizionalmente - ✅
Convert.ToInt32()per numeri interi - ✅ Cambiare colore del testo con
ForeColor - ✅ Evento
KeyPressper filtrare input in tempo reale
📖 Teoria: Numeri Pari e Dispari
Un numero è pari se è divisibile per 2 senza resto (resto = 0).
Un numero è dispari se diviso per 2 lascia resto 1.
// Esempi:
10 diviso 2 = 5 resto 0 → PARI
7 diviso 2 = 3 resto 1 → DISPARI
-4 diviso 2 = -2 resto 0 → PARI
0 diviso 2 = 0 resto 0 → PARI
// Operatore modulo (%):
10 % 2 = 0 // resto della divisione 10/2
7 % 2 = 1 // resto della divisione 7/2
// Regola generale:
if (numero % 2 == 0)
// PARI
else
// DISPARI
1
Progettazione dell’Interfaccia
| Tipo | Name | Text | Note |
|---|---|---|---|
| Label | lblTitolo | “Inserisci un Numero:” | – |
| TextBox | txtNumero |
vuoto | Input numero intero |
| Button | btnVerifica |
“Verifica” | – |
| Label | lblRisultato |
vuoto | Font: 14pt, Bold |
2
Codice Completo con Spiegazione
using System;
using System.Drawing;
using System.Windows.Forms;
namespace VerificaPariDispari
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// EVENTO: Click del pulsante "Verifica"
// ═══════════════════════════════════════════════════════
private void btnVerifica_Click(object sender, EventArgs e)
{
// ─────────────────────────────────────────────────
// STEP 1: Validazione campo vuoto
// ─────────────────────────────────────────────────
if (string.IsNullOrEmpty(txtNumero.Text))
{
lblRisultato.Text = "⚠️ Inserisci un numero!";
lblRisultato.ForeColor = Color.Gray;
return;
}
try
{
// ─────────────────────────────────────────────
// STEP 2: Conversione in intero
// ─────────────────────────────────────────────
// Convert.ToInt32() converte in numero intero (int)
// a differenza di ToDouble(), ToInt32() non accetta decimali
int numero = Convert.ToInt32(txtNumero.Text);
// ─────────────────────────────────────────────
// STEP 3: Verifica con operatore modulo (%)
// ─────────────────────────────────────────────
if (numero % 2 == 0)
{
// Resto = 0 → PARI
lblRisultato.Text = $"{numero} è un numero PARI ✅";
lblRisultato.ForeColor = Color.Blue;
}
else
{
// Resto = 1 → DISPARI
lblRisultato.Text = $"{numero} è un numero DISPARI ⚡";
lblRisultato.ForeColor = Color.Red;
}
}
catch (FormatException)
{
// L'utente ha inserito testo non numerico
lblRisultato.Text = "❌ Inserisci un numero intero valido!";
lblRisultato.ForeColor = Color.Black;
}
catch (OverflowException)
{
// Il numero è troppo grande per un int
lblRisultato.Text = "❌ Numero troppo grande!";
lblRisultato.ForeColor = Color.Black;
}
catch (Exception ex)
{
lblRisultato.Text = "❌ Errore: " + ex.Message;
lblRisultato.ForeColor = Color.Black;
}
}
}
}
🔍 Analisi Operatore Modulo (%):
// L'operatore % restituisce il RESTO della divisione int numero = 10; int resto = numero % 2; // 10 diviso 2 = 5 con resto 0 // resto = 0 int numero2 = 7; int resto2 = numero2 % 2; // 7 diviso 2 = 3 con resto 1 // resto2 = 1 // Altri esempi: 10 % 3 = 1 // 10 / 3 = 3 resto 1 15 % 4 = 3 // 15 / 4 = 3 resto 3 20 % 5 = 0 // 20 / 5 = 4 resto 0 (divisibile perfettamente)
Il modulo è utile per verificare divisibilità: se numero % divisore == 0,
il numero è divisibile perfettamente.
3
Miglioramento: Filtrare Input con KeyPress
Aggiungiamo l’evento KeyPress per permettere solo numeri e il segno meno
(per numeri negativi). Questo previene errori prima ancora che l’utente clicchi “Verifica”.
// ═══════════════════════════════════════════════════════
// EVENTO: KeyPress - Filtra caratteri non numerici
// ═══════════════════════════════════════════════════════
private void txtNumero_KeyPress(object sender, KeyPressEventArgs e)
{
// char.IsControl() verifica se è un tasto di controllo (Backspace, Tab, ecc.)
// char.IsDigit() verifica se è una cifra (0-9)
bool isNumero = char.IsDigit(e.KeyChar);
bool isControllo = char.IsControl(e.KeyChar);
bool isMeno = e.KeyChar == '-';
// Permetti SOLO:
// - Numeri (0-9)
// - Tasti di controllo (Backspace, Delete, ecc.)
// - Segno meno (-)
if (!isNumero && !isControllo && !isMeno)
{
e.Handled = true; // ❌ Blocca il tasto
return;
}
// Permetti il segno meno SOLO all'inizio
if (isMeno)
{
TextBox txt = (TextBox)sender;
// Se il segno meno non è all'inizio o c'è già un meno
if (txt.Text.IndexOf('-') > -1 || txt.SelectionStart != 0)
{
e.Handled = true; // ❌ Blocca
}
}
}
⚡ Come Collegare l’Evento KeyPress:
- Seleziona
txtNumeronel Designer - F4 → Fulmine ⚡ → Trova KeyPress
- Fai doppio click su KeyPress
- Scrivi il codice sopra nel metodo generato
🎬 Cosa Succede con KeyPress:
- Utente prova a scrivere “a” → KeyPress si attiva
char.IsDigit('a')= falsechar.IsControl('a')= false'a' == '-'= falsee.Handled = true→ ❌ “a” viene bloccato!- Utente prova a scrivere “5” →
char.IsDigit('5')= true - Tasto permesso → ✅ “5” viene inserito in txtNumero
📚 Nuovi Metodi e Concetti – Esercizio 2
Converte una stringa in numero intero a 32 bit (int). Non accetta decimali.
// Sintassi:
int numero = Convert.ToInt32(stringa);
// Esempi:
Convert.ToInt32("123") // 123
Convert.ToInt32("-45") // -45
Convert.ToInt32("0") // 0
Convert.ToInt32("12.5") // ❌ FormatException (ha decimali!)
Convert.ToInt32("abc") // ❌ FormatException
// Differenza con ToDouble():
Convert.ToDouble("12.5") // ✅ 12.5 (accetta decimali)
Convert.ToInt32("12.5") // ❌ Errore (non accetta decimali)
// Quando usare ToInt32 vs ToDouble:
// ToInt32 → Età, quantità, contatori (numeri interi)
// ToDouble → Peso, altezza, prezzi (numeri decimali)
Restituisce il resto della divisione tra due numeri. Fondamentale per verificare divisibilità.
// Sintassi:
int resto = dividendo % divisore;
// Esempi:
10 % 2 = 0 // 10 / 2 = 5 resto 0
10 % 3 = 1 // 10 / 3 = 3 resto 1
15 % 4 = 3 // 15 / 4 = 3 resto 3
20 % 5 = 0 // 20 / 5 = 4 resto 0
// Applicazioni pratiche:
// 1. Verificare se pari o dispari:
if (numero % 2 == 0)
Console.WriteLine("Pari");
// 2. Verificare se multiplo di 3:
if (numero % 3 == 0)
Console.WriteLine("Multiplo di 3");
// 3. Alternare colori in una lista (pari=blu, dispari=rosso):
if (indice % 2 == 0)
colore = Color.Blue;
else
colore = Color.Red;
Esegue blocchi di codice diversi in base a una condizione booleana (true/false).
// Struttura base:
if (condizione)
{
// Eseguito se condizione è true
}
else
{
// Eseguito se condizione è false
}
// Esempio pratico:
int eta = 18;
if (eta >= 18)
{
MessageBox.Show("Maggiorenne");
}
else
{
MessageBox.Show("Minorenne");
}
// if-else if-else (condizioni multiple):
int voto = 85;
if (voto >= 90)
{
lblGiudizio.Text = "Eccellente";
}
else if (voto >= 80)
{
lblGiudizio.Text = "Ottimo";
}
else if (voto >= 70)
{
lblGiudizio.Text = "Buono";
}
else
{
lblGiudizio.Text = "Sufficiente";
}
Proprietà che imposta il colore del testo di un controllo.
// Sintassi:
controllo.ForeColor = Color.NomeColore;
// Colori predefiniti:
lblRisultato.ForeColor = Color.Red;
lblRisultato.ForeColor = Color.Green;
lblRisultato.ForeColor = Color.Blue;
lblRisultato.ForeColor = Color.Orange;
lblRisultato.ForeColor = Color.Black;
lblRisultato.ForeColor = Color.Gray;
// Colore personalizzato RGB:
lblRisultato.ForeColor = Color.FromArgb(255, 100, 50);
// FromArgb(rosso, verde, blu) - valori da 0 a 255
// Uso pratico con feedback:
if (valido)
{
lblMessaggio.Text = "✅ Corretto!";
lblMessaggio.ForeColor = Color.Green;
}
else
{
lblMessaggio.Text = "❌ Errore!";
lblMessaggio.ForeColor = Color.Red;
}
Metodi statici per verificare il tipo di carattere.
// char.IsDigit(char) - verifica se è una cifra (0-9)
char.IsDigit('5') // true
char.IsDigit('a') // false
char.IsDigit(' ') // false
// char.IsControl(char) - verifica se è un carattere di controllo
char.IsControl('\b') // true (backspace)
char.IsControl('\t') // true (tab)
char.IsControl('a') // false
// char.IsLetter(char) - verifica se è una lettera
char.IsLetter('M') // true
char.IsLetter('5') // false
// Uso in KeyPress:
private void txt_KeyPress(object sender, KeyPressEventArgs e)
{
// Permetti solo numeri e backspace
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true; // Blocca
}
}
Restituisce la posizione (indice) della prima occorrenza di un carattere nella stringa. Ritorna -1 se non trovato.
// Sintassi:
int posizione = stringa.IndexOf(carattere);
// Esempi:
"Hello".IndexOf('e') // 1 (posizione 0=H, 1=e)
"Hello".IndexOf('o') // 4
"Hello".IndexOf('x') // -1 (non trovato)
"mario@email.com".IndexOf('@') // 5
// Uso pratico - verificare se contiene un carattere:
if (txtNumero.Text.IndexOf('-') > -1)
{
// La stringa contiene il segno meno
}
// Alternativa più leggibile:
if (txtNumero.Text.Contains("-"))
{
// Stesso risultato, sintassi più chiara
}
Proprietà che indica la posizione del cursore nella TextBox (indice del carattere).
// Posizione cursore:
txtNome.SelectionStart // 0 = inizio, 5 = dopo 5 caratteri
// Esempio - permetti '-' solo all'inizio:
if (e.KeyChar == '-' && txtNumero.SelectionStart != 0)
{
e.Handled = true; // Blocca se non è all'inizio
}
// Spostare il cursore programmaticamente:
txtNome.SelectionStart = 0; // Cursore all'inizio
txtNome.SelectionStart = txtNome.Text.Length; // Cursore alla fine
📊 Esercizio 3: Valutazione del Voto con Switch
▶ Obiettivo
Creare un’applicazione che converte un voto numerico (0-100) in una valutazione letterale
(Eccellente, Molto Buono, Buono, Sufficiente, Insufficiente). Introduce la struttura
switch come alternativa a lunghe catene di if-else.
🎯 Nuovi Concetti:
- ✅ Struttura
switchper valutare condizioni multiple - ✅ Pattern matching con range (
>= e <) - ✅ Combinare validazione e logica complessa
- ✅ Feedback colorato dinamico basato su valutazione
📖 Scala di Valutazione:
| Voto Numerico | Valutazione | Colore |
|---|---|---|
| 90 – 100 | ECCELLENTE | ● Verde |
| 80 – 89 | MOLTO BUONO | ● Verde Scuro |
| 70 – 79 | BUONO | ● Blu |
| 60 – 69 | SUFFICIENTE | ● Arancione |
| 0 – 59 | INSUFFICIENTE | ● Rosso |
1
Progettazione dell’Interfaccia
| Tipo | Name | Text | Note |
|---|---|---|---|
| Label | lblTitolo | “Inserisci il Voto (0-100):” | – |
| TextBox | txtVoto |
vuoto | Input voto numerico |
| Button | btnValuta |
“Valuta” | – |
| Label | lblValutazione |
vuoto | Font: 16pt, Bold |
2
Codice con Switch Statement
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ValutazioneVoto
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// EVENTO: Click del pulsante "Valuta"
// ═══════════════════════════════════════════════════════
private void btnValuta_Click(object sender, EventArgs e)
{
// ─────────────────────────────────────────────────
// STEP 1: Validazione campo vuoto
// ─────────────────────────────────────────────────
if (string.IsNullOrEmpty(txtVoto.Text))
{
lblValutazione.Text = "⚠️ Inserisci un voto!";
lblValutazione.ForeColor = Color.Gray;
return;
}
try
{
// ─────────────────────────────────────────────
// STEP 2: Conversione e validazione range
// ─────────────────────────────────────────────
int voto = Convert.ToInt32(txtVoto.Text);
// Validazione: voto deve essere tra 0 e 100
if (voto < 0 || voto > 100)
{
lblValutazione.Text = "❌ Il voto deve essere tra 0 e 100!";
lblValutazione.ForeColor = Color.Black;
return;
}
// ─────────────────────────────────────────────
// STEP 3: Valutazione con SWITCH (C# 9.0+)
// ─────────────────────────────────────────────
string valutazione;
Color colore;
// Switch con pattern matching (range)
switch (voto)
{
case >= 90 and <= 100: valutazione = "ECCELLENTE 🏆"; colore = Color.Green; break; case >= 80 and < 90: valutazione = "MOLTO BUONO ⭐"; colore = Color.DarkGreen; break; case >= 70 and < 80: valutazione = "BUONO ✅"; colore = Color.Blue; break; case >= 60 and < 70: valutazione = "SUFFICIENTE ✔️"; colore = Color.Orange; break; case >= 0 and < 60:
valutazione = "INSUFFICIENTE ❌";
colore = Color.Red;
break;
default:
// Questo non dovrebbe mai verificarsi grazie alla validazione sopra
valutazione = "Voto non valido";
colore = Color.Black;
break;
}
// ─────────────────────────────────────────────
// STEP 4: Visualizzazione risultato
// ─────────────────────────────────────────────
lblValutazione.Text = $"Voto {voto}: {valutazione}";
lblValutazione.ForeColor = colore;
}
catch (FormatException)
{
lblValutazione.Text = "❌ Inserisci un voto numerico valido!";
lblValutazione.ForeColor = Color.Black;
}
catch (Exception ex)
{
lblValutazione.Text = "❌ Errore: " + ex.Message;
lblValutazione.ForeColor = Color.Black;
}
}
}
}
📝 NOTA: Versione Compatibile per Visual Studio Vecchio
Il codice sopra usa il pattern matching di C# 9.0+
(case >= 90 and <= 100). Se il tuo Visual Studio non lo supporta,
usa questa versione alternativa con if-else:
// Versione con if-else (funziona su tutte le versioni C#)
string valutazione;
Color colore;
if (voto >= 90 && voto <= 100) { valutazione = "ECCELLENTE 🏆"; colore = Color.Green; } else if (voto >= 80 && voto < 90) { valutazione = "MOLTO BUONO ⭐"; colore = Color.DarkGreen; } else if (voto >= 70 && voto < 80) { valutazione = "BUONO ✅"; colore = Color.Blue; } else if (voto >= 60 && voto < 70)
{
valutazione = "SUFFICIENTE ✔️";
colore = Color.Orange;
}
else // voto < 60
{
valutazione = "INSUFFICIENTE ❌";
colore = Color.Red;
}
lblValutazione.Text = $"Voto {voto}: {valutazione}";
lblValutazione.ForeColor = colore;
🔍 Confronto: Switch vs If-Else
✅ Quando usare SWITCH:
- Quando hai molte condizioni basate sullo stesso valore
- Quando le condizioni sono discrete (valori specifici o range)
- Codice più leggibile con molti casi
✅ Quando usare IF-ELSE:
- Quando le condizioni sono complesse (più variabili)
- Quando hai poche condizioni (2-3)
- Quando usi il pattern matching moderno (
>= and <) non supportato
// Switch moderno (C# 9.0+) - Elegante per range
switch (voto)
{
case >= 90 and <= 100: // ... break; } // If-else - Più verboso ma universale if (voto >= 90 && voto <= 100)
{
// ...
}
// Switch classico - Solo per valori esatti
switch (giorno)
{
case 1:
nome = "Lunedì";
break;
case 2:
nome = "Martedì";
break;
}
3
Validazione Avanzata con KeyPress
// ═══════════════════════════════════════════════════════
// EVENTO: KeyPress - Permetti solo numeri 0-9
// ═══════════════════════════════════════════════════════
private void txtVoto_KeyPress(object sender, KeyPressEventArgs e)
{
// Permetti solo numeri e backspace (NO segno meno)
if (!char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true; // Blocca il tasto
}
}
📚 Nuovi Concetti – Esercizio 3
Struttura di controllo per eseguire codice diverso in base al valore di un’espressione.
// Sintassi base:
switch (variabile)
{
case valore1:
// Codice se variabile == valore1
break;
case valore2:
// Codice se variabile == valore2
break;
default:
// Codice se nessun case corrisponde
break;
}
// Esempio: giorni della settimana
int giorno = 3;
string nomeGiorno;
switch (giorno)
{
case 1:
nomeGiorno = "Lunedì";
break;
case 2:
nomeGiorno = "Martedì";
break;
case 3:
nomeGiorno = "Mercoledì";
break;
default:
nomeGiorno = "Giorno non valido";
break;
}
// IMPORTANTE: break è obbligatorio!
// Senza break, il codice continua nei case successivi
Sintassi moderna per verificare se un valore rientra in un intervallo usando and.
// Sintassi moderna:
switch (numero)
{
case >= 90 and <= 100: // numero è tra 90 e 100 (inclusi) break; case >= 80 and < 90: // numero è tra 80 e 89 break; } // Equivalente con if-else: if (numero >= 90 && numero <= 100) { // ... } else if (numero >= 80 && numero < 90) { // ... } // Altri pattern: switch (valore) { case > 0: // maggiore di 0
break;
case < 0: // minore di 0
break;
case 0: // uguale a 0
break;
}
Se non disponibile, usa
if-else.Restituisce true solo se TUTTE le condizioni sono vere.
// Tabella di verità:
true && true // true
true && false // false
false && false // false
// Uso per validare range:
if (voto >= 0 && voto <= 100) { // voto è valido solo se >= 0 E <= 100 } // Differenza con || (OR): // && → TUTTE devono essere vere // || → ALMENO UNA deve essere vera // Esempio pratico: if (eta >= 18 && patente == true)
{
// Può guidare SOLO se ha 18 anni E ha la patente
}
// Condizioni multiple:
if (nome != "" && cognome != "" && email.Contains("@"))
{
// Tutti e 3 devono essere veri
}
Interrompe l’esecuzione di un blocco switch o di un ciclo.
// In switch - OBBLIGATORIO dopo ogni case:
switch (valore)
{
case 1:
Console.WriteLine("Uno");
break; // Esce dallo switch
case 2:
Console.WriteLine("Due");
break; // Senza break, errore di compilazione!
}
// In cicli (vedremo nelle prossime lezioni):
for (int i = 0; i < 10; i++)
{
if (i == 5)
break; // Esce dal ciclo quando i è 5
}
// Cosa succede SENZA break?
switch (valore)
{
case 1:
Console.WriteLine("Uno");
// ❌ ERRORE: manca break!
// Il codice "cade" nel case successivo
case 2:
Console.WriteLine("Due");
break;
}
🧮 Esercizio 4: Calcolatrice con 4 Operazioni
▶ Obiettivo
Creare una calcolatrice completa che esegue le quattro operazioni fondamentali
(somma, sottrazione, moltiplicazione, divisione) con gestione completa degli errori,
inclusa la divisione per zero.
🎯 Cosa Imparerai:
- ✅ Gestire più operazioni con un unico metodo helper
- ✅ Validazione avanzata (divisione per zero)
- ✅ Abilitare/disabilitare pulsanti dinamicamente
- ✅ Organizzare codice con metodi riutilizzabili
- ✅ Operatori aritmetici:
+,-,*,/
1
Progettazione dell’Interfaccia
| Tipo | Name | Text | Note |
|---|---|---|---|
| Label | lblNumero1 | “Primo Numero:” | – |
| TextBox | txtNumero1 |
vuoto | – |
| Label | lblNumero2 | “Secondo Numero:” | – |
| TextBox | txtNumero2 |
vuoto | – |
| Button | btnSomma |
“+” | Enabled = false |
| Button | btnSottrai |
“-“ | Enabled = false |
| Button | btnMoltiplica |
“×” | Enabled = false |
| Button | btnDividi |
“÷” | Enabled = false |
| Label | lblOperazione |
“Seleziona operazione” | Font: 10pt |
| Label | lblRisultato |
“” | Font: 16pt, Bold |
2
Codice Completo della Calcolatrice
using System;
using System.Drawing;
using System.Windows.Forms;
namespace CalcolatriceCompleta
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// EVENTO FORM LOAD: Inizializzazione
// ═══════════════════════════════════════════════════════
private void Form1_Load(object sender, EventArgs e)
{
// Inizializza l'interfaccia all'avvio
lblOperazione.Text = "Seleziona un'operazione";
lblRisultato.Text = "";
// Disabilita tutti i pulsanti (abilitati quando i numeri sono validi)
AbilitaPulsanti(false);
}
// ═══════════════════════════════════════════════════════
// EVENTI: Click dei pulsanti operazione
// ═══════════════════════════════════════════════════════
private void btnSomma_Click(object sender, EventArgs e)
{
CalcolaOperazione('+');
}
private void btnSottrai_Click(object sender, EventArgs e)
{
CalcolaOperazione('-');
}
private void btnMoltiplica_Click(object sender, EventArgs e)
{
CalcolaOperazione('*');
}
private void btnDividi_Click(object sender, EventArgs e)
{
CalcolaOperazione('/');
}
// ═══════════════════════════════════════════════════════
// METODO PRINCIPALE: Calcola operazione
// ═══════════════════════════════════════════════════════
private void CalcolaOperazione(char operatore)
{
// Validazione campi
if (string.IsNullOrEmpty(txtNumero1.Text) ||
string.IsNullOrEmpty(txtNumero2.Text))
{
lblRisultato.Text = "⚠️ Inserisci entrambi i numeri!";
lblRisultato.ForeColor = Color.Red;
return;
}
try
{
// Conversione numeri
double num1 = Convert.ToDouble(txtNumero1.Text);
double num2 = Convert.ToDouble(txtNumero2.Text);
double risultato = 0;
bool operazioneValida = true;
string nomeOperazione = "";
// ─────────────────────────────────────────────
// Esegui operazione in base al carattere
// ─────────────────────────────────────────────
switch (operatore)
{
case '+':
risultato = num1 + num2;
nomeOperazione = "Somma";
break;
case '-':
risultato = num1 - num2;
nomeOperazione = "Sottrazione";
break;
case '*':
risultato = num1 * num2;
nomeOperazione = "Moltiplicazione";
break;
case '/':
// IMPORTANTE: Gestione divisione per zero
if (num2 != 0)
{
risultato = num1 / num2;
nomeOperazione = "Divisione";
}
else
{
lblRisultato.Text = "❌ Errore: divisione per zero!";
lblRisultato.ForeColor = Color.Red;
lblOperazione.Text = "Non puoi dividere per zero";
operazioneValida = false;
}
break;
}
// Mostra risultato se operazione valida
if (operazioneValida)
{
lblOperazione.Text = $"Operazione: {nomeOperazione}";
lblRisultato.Text = $"Risultato: {risultato:F2}";
lblRisultato.ForeColor = Color.Green;
}
}
catch (FormatException)
{
lblRisultato.Text = "❌ Inserisci valori numerici validi!";
lblRisultato.ForeColor = Color.Red;
}
catch (Exception ex)
{
lblRisultato.Text = $"❌ Errore: {ex.Message}";
lblRisultato.ForeColor = Color.Red;
}
}
// ═══════════════════════════════════════════════════════
// EVENTI: TextChanged per validazione dinamica
// ═══════════════════════════════════════════════════════
private void txtNumero1_TextChanged(object sender, EventArgs e)
{
AbilitaPulsanti(ValidaInput());
}
private void txtNumero2_TextChanged(object sender, EventArgs e)
{
AbilitaPulsanti(ValidaInput());
}
// ═══════════════════════════════════════════════════════
// METODO HELPER: Valida che entrambi i campi siano numeri
// ═══════════════════════════════════════════════════════
private bool ValidaInput()
{
try
{
if (!string.IsNullOrEmpty(txtNumero1.Text))
Convert.ToDouble(txtNumero1.Text);
if (!string.IsNullOrEmpty(txtNumero2.Text))
Convert.ToDouble(txtNumero2.Text);
return true;
}
catch
{
return false;
}
}
// ═══════════════════════════════════════════════════════
// METODO HELPER: Abilita/disabilita pulsanti operazione
// ═══════════════════════════════════════════════════════
private void AbilitaPulsanti(bool abilita)
{
btnSomma.Enabled = abilita;
btnSottrai.Enabled = abilita;
btnMoltiplica.Enabled = abilita;
btnDividi.Enabled = abilita;
}
}
}
🔍 Analisi del Design Pattern:
Nota come il codice è organizzato in metodi riutilizzabili:
CalcolaOperazione(char operatore):
Metodo generico che funziona per tutte le 4 operazioni.
Riceve il simbolo dell’operazione come parametro.ValidaInput():
Metodo separato per validazione, riutilizzato in 2 punti diversi.AbilitaPulsanti(bool abilita):
Metodo che abilita/disabilita tutti i 4 pulsanti con una sola chiamata.
Questo è un esempio di codice DRY (Don’t Repeat Yourself):
scriviamo la logica una volta e la riusiamo dove serve!
⚠️ Gestione Divisione per Zero:
case '/':
if (num2 != 0)
{
risultato = num1 / num2;
}
else
{
// Divisione per zero = ERRORE MATEMATICO
lblRisultato.Text = "❌ Divisione per zero!";
operazioneValida = false;
}
break;
La divisione per zero è un errore matematico
(risultato = infinito, indefinito). Dobbiamo sempre controllare
che il divisore sia diverso da zero prima di eseguire la divisione.
3
🎬 Flusso di Esecuzione Completo
Scenario: Calcolare 10 + 5
- Avvio applicazione:
- Form1_Load si attiva
- Tutti i pulsanti vengono disabilitati (
Enabled = false)
- Utente scrive “10” in txtNumero1:
- Evento
txtNumero1_TextChanged - Chiama
ValidaInput()→ txtNumero2 è vuoto → return false AbilitaPulsanti(false)→ Pulsanti ancora disabilitati
- Evento
- Utente scrive “5” in txtNumero2:
- Evento
txtNumero2_TextChanged - Chiama
ValidaInput()→ Entrambi sono numeri → return true AbilitaPulsanti(true)→ ✅ Pulsanti si abilitano!
- Evento
- Utente clicca sul pulsante “+”:
- Evento
btnSomma_Click - Chiama
CalcolaOperazione('+') - Converte: num1 = 10, num2 = 5
- Switch:
case '+'→risultato = 10 + 5 = 15 - Mostra: “Risultato: 15.00” (verde)
- lblOperazione: “Operazione: Somma”
- Evento
📚 Operatori Aritmetici in C#
Somma due numeri. Con stringhe, concatena (unisce) le stringhe.
// Con numeri: int risultato = 10 + 5; // 15 double somma = 3.5 + 2.1; // 5.6 // Con stringhe (concatenazione): string nome = "Mario" + " " + "Rossi"; // "Mario Rossi" string testo = "Voto: " + 85; // "Voto: 85"
Sottrae il secondo numero dal primo.
int risultato = 10 - 5; // 5 double differenza = 7.8 - 2.3; // 5.5 // Con numeri negativi: int x = 10 - 15; // -5
Moltiplica due numeri.
int risultato = 10 * 5; // 50 double prodotto = 2.5 * 4; // 10.0 // Calcolo area rettangolo: double larghezza = 5.0; double altezza = 3.0; double area = larghezza * altezza; // 15.0
Divide il primo numero per il secondo. ATTENZIONE: La divisione per zero genera errore!
double risultato = 10.0 / 2.0; // 5.0
double quoziente = 7.0 / 2.0; // 3.5
// IMPORTANTE: Divisione interi vs decimali
int a = 7 / 2; // 3 (divisione intera, perde decimali!)
double b = 7.0 / 2.0; // 3.5 (divisione decimale)
double c = 7 / 2; // 3.0 (converti almeno uno in double!)
// Gestione divisione per zero:
double divisore = 0;
if (divisore != 0)
{
double risultato = 10 / divisore;
}
else
{
// Errore: divisione per zero!
}
Gli operatori hanno un ordine di esecuzione (come in matematica).
// Ordine di precedenza (dal più alto al più basso): // 1. Parentesi () // 2. Moltiplicazione * e Divisione / // 3. Somma + e Sottrazione - int risultato1 = 10 + 5 * 2; // 20 (prima 5*2=10, poi 10+10) int risultato2 = (10 + 5) * 2; // 30 (prima 10+5=15, poi 15*2) double calc = 10 + 20 / 2 - 3; // 17 // Esecuzione: 20/2=10 → 10+10=20 → 20-3=17 // Best Practice: Usa parentesi per chiarezza! double media = (voto1 + voto2 + voto3) / 3; // ✅ Chiaro double media2 = voto1 + voto2 + voto3 / 3; // ❌ Confuso!
🌡️ Esercizio 5: Convertitore di Temperatura
▶ Obiettivo
Creare un convertitore che trasforma temperature da Celsius a Fahrenheit e viceversa.
Introduce l’uso di RadioButton per selezionare opzioni mutuamente esclusive
e formule matematiche più complesse.
🎯 Nuovi Concetti:
- ✅ RadioButton: Controlli per scelte esclusive (o questo o quello)
- ✅ RadioButton.Checked: Verificare quale opzione è selezionata
- ✅ Formule matematiche: Applicare conversioni con precedenza operatori
- ✅ CheckedChanged: Evento quando cambia selezione RadioButton
- ✅ Aggiornamento dinamico dell’interfaccia
📖 Formule di Conversione:
🔥 Da Celsius a Fahrenheit:
F = C × 9/5 + 32 // Esempi: 0°C = 0 × 9/5 + 32 = 32°F (punto di congelamento acqua) 100°C = 100 × 9/5 + 32 = 212°F (punto di ebollizione acqua) 37°C = 37 × 9/5 + 32 = 98.6°F (temperatura corporea)
❄️ Da Fahrenheit a Celsius:
C = (F - 32) × 5/9 // Esempi: 32°F = (32 - 32) × 5/9 = 0°C 212°F = (212 - 32) × 5/9 = 100°C 98.6°F = (98.6 - 32) × 5/9 = 37°C
1
Progettazione dell’Interfaccia
| Tipo | Name | Text | Note |
|---|---|---|---|
| Label | lblTitolo |
“Convertitore di Temperatura” | Font: 14pt, Bold |
| Label | lblTemperatura | “Temperatura:” | – |
| TextBox | txtTemperatura |
vuoto | Input temperatura |
| Label | lblTipoConversione | “Tipo di Conversione:” | Font: Bold |
| RadioButton | rbCelsius |
“Celsius → Fahrenheit” | Checked = true |
| RadioButton | rbFahrenheit |
“Fahrenheit → Celsius” | Checked = false |
| Button | btnConverti |
“Converti” | – |
| Label | lblRisultato |
vuoto | Font: 14pt, Bold |
💡 Suggerimento Layout:
Posiziona i due RadioButton uno sotto l’altro, vicini tra loro.
Visual Studio raggruppa automaticamente i RadioButton sullo stesso Form/Panel:
quando ne selezioni uno, l’altro si deseleziona automaticamente.
2
Codice Completo del Convertitore
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ConvertitoreTemperatura
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// ═══════════════════════════════════════════════════════
// EVENTO: Click del pulsante "Converti"
// ═══════════════════════════════════════════════════════
private void btnConverti_Click(object sender, EventArgs e)
{
// ─────────────────────────────────────────────────
// STEP 1: Validazione campo vuoto
// ─────────────────────────────────────────────────
if (string.IsNullOrEmpty(txtTemperatura.Text))
{
lblRisultato.Text = "⚠️ Inserisci una temperatura!";
lblRisultato.ForeColor = Color.Gray;
return;
}
try
{
// ─────────────────────────────────────────────
// STEP 2: Conversione valore temperatura
// ─────────────────────────────────────────────
double temperatura = Convert.ToDouble(txtTemperatura.Text);
double risultato;
string unitaPartenza;
string unitaArrivo;
// ─────────────────────────────────────────────
// STEP 3: Determina tipo conversione con RadioButton
// ─────────────────────────────────────────────
if (rbCelsius.Checked)
{
// Converti da Celsius a Fahrenheit
// Formula: F = C × 9/5 + 32
risultato = temperatura * 9.0 / 5.0 + 32;
unitaPartenza = "°C";
unitaArrivo = "°F";
}
else // rbFahrenheit.Checked
{
// Converti da Fahrenheit a Celsius
// Formula: C = (F - 32) × 5/9
risultato = (temperatura - 32) * 5.0 / 9.0;
unitaPartenza = "°F";
unitaArrivo = "°C";
}
// ─────────────────────────────────────────────
// STEP 4: Visualizzazione risultato formattato
// ─────────────────────────────────────────────
// Formato: "25°C = 77°F"
lblRisultato.Text = $"{temperatura:F1}{unitaPartenza} = {risultato:F1}{unitaArrivo}";
lblRisultato.ForeColor = Color.Blue;
}
catch (FormatException)
{
lblRisultato.Text = "❌ Inserisci un valore numerico valido!";
lblRisultato.ForeColor = Color.Red;
}
catch (Exception ex)
{
lblRisultato.Text = $"❌ Errore: {ex.Message}";
lblRisultato.ForeColor = Color.Red;
}
}
// ═══════════════════════════════════════════════════════
// EVENTI: CheckedChanged - Quando cambia selezione RadioButton
// ═══════════════════════════════════════════════════════
private void rbCelsius_CheckedChanged(object sender, EventArgs e)
{
// Aggiorna l'interfaccia quando cambia la selezione
AggiornaInterfaccia();
}
private void rbFahrenheit_CheckedChanged(object sender, EventArgs e)
{
AggiornaInterfaccia();
}
// ═══════════════════════════════════════════════════════
// METODO HELPER: Aggiorna testi interfaccia
// ═══════════════════════════════════════════════════════
private void AggiornaInterfaccia()
{
if (rbCelsius.Checked)
{
lblTitolo.Text = "🔥 Converti da Celsius a Fahrenheit";
lblTemperatura.Text = "Temperatura (°C):";
}
else
{
lblTitolo.Text = "❄️ Converti da Fahrenheit a Celsius";
lblTemperatura.Text = "Temperatura (°F):";
}
// Pulisce il risultato precedente
lblRisultato.Text = "";
}
}
}
🔍 Analisi delle Formule:
1️⃣ Celsius → Fahrenheit:
// Formula: F = C × 9/5 + 32
risultato = temperatura * 9.0 / 5.0 + 32;
// IMPORTANTE: Usa 9.0 e 5.0 (con decimali)!
// Sbagliato: 9/5 = 1 (divisione intera)
// Corretto: 9.0/5.0 = 1.8 (divisione decimale)
// Esempio: 25°C
risultato = 25 * 9.0 / 5.0 + 32
= 25 * 1.8 + 32
= 45 + 32
= 77°F
2️⃣ Fahrenheit → Celsius:
// Formula: C = (F - 32) × 5/9
risultato = (temperatura - 32) * 5.0 / 9.0;
// IMPORTANTE: Parentesi sono fondamentali!
// Sbagliato: temperatura - 32 * 5.0 / 9.0
// (moltiplicazione prima della sottrazione)
// Corretto: (temperatura - 32) * 5.0 / 9.0
// (sottrazione prima, poi moltiplicazione)
// Esempio: 77°F
risultato = (77 - 32) * 5.0 / 9.0
= 45 * 5.0 / 9.0
= 225.0 / 9.0
= 25°C
💡 Perché 9.0 e 5.0 invece di 9 e 5?
In C#, la divisione tra numeri interi produce un risultato intero (perde i decimali):
// Divisione INTERA (entrambi int): int a = 9 / 5; // 1 (perde .8) int b = 7 / 2; // 3 (perde .5) // Divisione DECIMALE (almeno uno è double): double c = 9.0 / 5.0; // 1.8 ✅ double d = 9.0 / 5; // 1.8 ✅ (basta uno double) double e = 9 / 5.0; // 1.8 ✅ // Nel convertitore: // ❌ SBAGLIATO (perde decimali): risultato = temperatura * 9 / 5 + 32; // 25 * 9 / 5 + 32 = 25 * 1 + 32 = 57 (ERRORE!) // ✅ CORRETTO (mantiene decimali): risultato = temperatura * 9.0 / 5.0 + 32; // 25 * 9.0 / 5.0 + 32 = 25 * 1.8 + 32 = 77
3
🎬 Flusso di Esecuzione: Convertire 0°C
- Avvio applicazione:
- rbCelsius è selezionato di default (Checked = true)
- lblTitolo: “🔥 Converti da Celsius a Fahrenheit”
- Utente scrive “0” in txtTemperatura
- Utente clicca “Converti”:
- Evento
btnConverti_Click - Validazione: campo non vuoto ✅
- Conversione:
temperatura = 0 - Verifica:
rbCelsius.Checked= true - Calcolo:
risultato = 0 * 9.0 / 5.0 + 32 = 32 - Mostra: “0.0°C = 32.0°F” (blu)
- Evento
- Utente clicca su rbFahrenheit:
- Evento
rbFahrenheit_CheckedChanged - rbCelsius automaticamente diventa Checked = false
- Chiama
AggiornaInterfaccia() - lblTitolo: “❄️ Converti da Fahrenheit a Celsius”
- lblRisultato: “” (pulito)
- Evento
- Utente scrive “32” e clicca “Converti”:
- temperatura = 32
- Verifica:
rbFahrenheit.Checked= true - Calcolo:
risultato = (32 - 32) * 5.0 / 9.0 = 0 - Mostra: “32.0°F = 0.0°C” (blu)
📚 Nuovi Controlli e Concetti – Esercizio 5
Controllo per selezionare una sola opzione tra un gruppo di scelte mutuamente esclusive.
// Caratteristiche RadioButton:
// 1. Solo UNO può essere selezionato alla volta
// 2. Selezionarne uno deseleziona automaticamente gli altri
// 3. Devono essere nello stesso contenitore (Form, Panel, GroupBox)
// Creazione:
RadioButton rbOpzione1 = new RadioButton();
rbOpzione1.Text = "Opzione 1";
rbOpzione1.Checked = true; // Selezionato
RadioButton rbOpzione2 = new RadioButton();
rbOpzione2.Text = "Opzione 2";
rbOpzione2.Checked = false; // Non selezionato
// Verifica quale è selezionato:
if (rbOpzione1.Checked)
{
// L'utente ha selezionato Opzione 1
}
else if (rbOpzione2.Checked)
{
// L'utente ha selezionato Opzione 2
}
Proprietà booleana che indica se il RadioButton è selezionato (true) o no (false).
// Leggere lo stato:
bool selezionato = rbCelsius.Checked;
// Impostare lo stato programmaticamente:
rbCelsius.Checked = true; // Seleziona questo
// Automaticamente rbFahrenheit diventa Checked = false
// Uso pratico:
if (rbCelsius.Checked)
{
// Esegui conversione Celsius → Fahrenheit
}
else
{
// Esegui conversione Fahrenheit → Celsius
}
Si attiva quando cambia lo stato Checked del RadioButton (da true a false o viceversa).
// Gestione evento:
private void rbCelsius_CheckedChanged(object sender, EventArgs e)
{
// Questo si attiva quando:
// - L'utente clicca su rbCelsius (diventa Checked = true)
// - L'utente clicca su rbFahrenheit (rbCelsius diventa Checked = false)
if (rbCelsius.Checked)
{
lblTitolo.Text = "Converti da Celsius";
}
}
// ATTENZIONE: Si attiva due volte quando cambi selezione:
// 1. Sul RadioButton che si DESELEZIONA (Checked passa da true a false)
// 2. Sul RadioButton che si SELEZIONA (Checked passa da false a true)
// Best Practice: Controlla sempre rbX.Checked prima di agire
private void RadioButton_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb = (RadioButton)sender;
if (rb.Checked) // Esegui solo se è quello selezionato
{
// Logica qui
}
}
Formatta un numero con 1 cifra decimale. Variante di :F2 visto negli esercizi precedenti.
double temperatura = 25.6789;
// Vari formati decimali:
$"{temperatura:F0}" // "26" (nessun decimale, arrotondato)
$"{temperatura:F1}" // "25.7" (1 decimale)
$"{temperatura:F2}" // "25.68" (2 decimali)
$"{temperatura:F3}" // "25.679" (3 decimali)
// Nel convertitore:
lblRisultato.Text = $"{temperatura:F1}°C = {risultato:F1}°F";
// Output: "25.7°C = 78.3°F"
// Alternativa senza formattazione:
lblRisultato.Text = temperatura + "°C = " + risultato + "°F";
// Output: "25.6789°C = 78.22202°F" (troppi decimali!)
Sintassi moderna per inserire variabili direttamente in una stringa usando ${variabile}.
// Metodo MODERNO (C# 6.0+) - String Interpolation:
string nome = "Mario";
int eta = 25;
string messaggio = $"Ciao {nome}, hai {eta} anni";
// Output: "Ciao Mario, hai 25 anni"
// Con formattazione:
double prezzo = 19.99;
string testo = $"Prezzo: €{prezzo:F2}";
// Output: "Prezzo: €19.99"
// Metodo VECCHIO - Concatenazione:
string messaggio2 = "Ciao " + nome + ", hai " + eta + " anni";
// Stesso risultato ma meno leggibile
// Metodo VECCHIO - String.Format:
string messaggio3 = String.Format("Ciao {0}, hai {1} anni", nome, eta);
// Best Practice: Usa String Interpolation $"..." quando possibile!
lblRisultato.Text = $"{temperatura:F1}°C = {risultato:F1}°F";
Le parentesi forzano l’ordine di esecuzione delle operazioni matematiche.
// CRUCIALE nelle formule di conversione! // ❌ SBAGLIATO (senza parentesi): risultato = temperatura - 32 * 5.0 / 9.0; // Esecuzione: 32 * 5.0 = 160.0 // 160.0 / 9.0 = 17.78 // temperatura - 17.78 // Per 77°F: 77 - 17.78 = 59.22 (ERRORE! Dovrebbe essere 25) // ✅ CORRETTO (con parentesi): risultato = (temperatura - 32) * 5.0 / 9.0; // Esecuzione: (77 - 32) = 45 // 45 * 5.0 = 225.0 // 225.0 / 9.0 = 25.0 (CORRETTO!) // Regola: Le parentesi hanno MASSIMA precedenza // Ordine senza parentesi: * / % → + - // Con parentesi: () → * / % → + - // Altri esempi: int x = 10 + 5 * 2; // 20 (prima 5*2=10, poi +10) int y = (10 + 5) * 2; // 30 (prima 10+5=15, poi 15*2) double z = 10 + 20 / 2; // 20 (prima 20/2=10, poi 10+10) double w = (10 + 20) / 2; // 15 (prima 10+20=30, poi 30/2)
🎓 Riepilogo Completo: Cosa Hai Imparato
✨ Competenze Acquisite in Questa Lezione
🔢 Operazioni Matematiche
- Somma (
+), sottrazione (-) - Moltiplicazione (
*), divisione (/) - Modulo (
%) per resto divisione - Precedenza operatori e uso parentesi
✅ Strutture Condizionali
if-elseper decisioni binarieif-else if-elseper condizioni multipleswitchper valutazioni discrete- Pattern matching con range (C# 9.0+)
🔄 Conversioni di Tipo
Convert.ToDouble()per decimaliConvert.ToInt32()per interi.ToString()per stringhe- Formattazione con
:F0,:F1,:F2
🛡️ Validazione Input
string.IsNullOrEmpty()- Gestione errori con
try-catch - Validazione range (es: 0-100)
- Filtro caratteri con
KeyPress
🎨 Feedback Visivo
- Cambiare colori con
ForeColor - Abilitare/disabilitare con
Enabled - Messaggi dinamici informativi
- Icone emoji per UX migliore
🎛️ Nuovi Controlli
- RadioButton: Scelte mutuamente esclusive
.Checkedper verificare selezione- Evento
CheckedChanged - Aggiornamento dinamico interfaccia
🏆 Tabella Riepilogativa Esercizi
| Esercizio | Concetti Chiave | Applicazione Pratica |
|---|---|---|
| 1. Somma Numeri | Conversioni, validazione, try-catch | Base per qualsiasi calcolatrice |
| 2. Pari/Dispari | Operatore %, if-else, KeyPress | Validazione numeri, filtri input |
| 3. Valutazione Voto | Switch, pattern matching, range | Sistemi di rating, classificazione |
| 4. Calcolatrice | 4 operatori, metodi helper, divisione zero | App calcolatrice completa |
| 5. Convertitore Temp | RadioButton, formule complesse, precedenza | Convertitori unità di misura |
💎 Best Practices: Lezioni Apprese
✅ Regole d’Oro della Programmazione
1️⃣ Valida SEMPRE l’Input Utente
Non fidarti mai di ciò che l’utente inserisce. Controlla sempre:
- ✅ Il campo è compilato? (
string.IsNullOrEmpty()) - ✅ Il valore è numerico? (
try-catchoTryParse) - ✅ È nel range corretto? (
if (voto >= 0 && voto <= 100)) - ✅ Casi speciali? (divisione per zero, valori negativi, ecc.)
2️⃣ Dai Feedback Visivo Immediato
L’utente deve sempre sapere cosa sta succedendo:
- 🟢 Verde: Operazione riuscita, valore valido
- 🔴 Rosso: Errore, valore non valido
- 🟠 Arancione: Avviso, attenzione richiesta
- 🔵 Blu: Informazione neutra, risultato
- ⚪ Grigio: Disabilitato, non disponibile
3️⃣ Scrivi Codice Leggibile
// ✅ BUONO - Leggibile
if (eta >= 18)
{
MessageBox.Show("Maggiorenne");
}
else
{
MessageBox.Show("Minorenne");
}
// ❌ CATTIVO - Compresso, illeggibile
if(eta>=18)MessageBox.Show("Maggiorenne");else MessageBox.Show("Minorenne");
// ✅ BUONO - Nomi significativi
double temperaturaFahrenheit = (celsius * 9.0 / 5.0) + 32;
// ❌ CATTIVO - Nomi vaghi
double x = (y * 9.0 / 5.0) + 32;
4️⃣ Usa try-catch per Conversioni
// ✅ BUONO - Gestisce errori
try
{
int numero = Convert.ToInt32(txtInput.Text);
// Usa numero sapendo che è valido
}
catch (FormatException)
{
lblErrore.Text = "Inserisci un numero valido!";
}
// ❌ CATTIVO - Può crashare
int numero = Convert.ToInt32(txtInput.Text); // 💥 Se non è numero, crash!
5️⃣ Attenzione ai Decimali nelle Divisioni
// ❌ SBAGLIATO - Divisione intera perde decimali double media = (voto1 + voto2 + voto3) / 3; // Se voto1=7, voto2=8, voto3=9 → (7+8+9)/3 = 24/3 = 8 (CORRETTO) // Se voto1=7, voto2=8, voto3=8 → (7+8+8)/3 = 23/3 = 7 (ERRORE! Dovrebbe essere 7.67) // ✅ CORRETTO - Almeno un operando deve essere double double media = (voto1 + voto2 + voto3) / 3.0; // 23 / 3.0 = 7.666... ✅ // Oppure converti esplicitamente: double media = (double)(voto1 + voto2 + voto3) / 3;
6️⃣ Usa Parentesi nelle Formule Complesse
Anche se conosci la precedenza degli operatori, le parentesi rendono il codice più chiaro:
// ✅ CHIARO - Parentesi esplicite double fahrenheit = (celsius * 9.0 / 5.0) + 32; double media = (voto1 + voto2 + voto3) / 3.0; // ❌ AMBIGUO - Precedenza implicita double fahrenheit = celsius * 9.0 / 5.0 + 32; // Funziona ma meno chiaro double media = voto1 + voto2 + voto3 / 3.0; // 💥 ERRORE! Divide solo voto3
❌ Errori Comuni da Evitare
1️⃣ Dimenticare la Gestione Errori
// ❌ PERICOLOSO
private void btnCalcola_Click(object sender, EventArgs e)
{
double num = Convert.ToDouble(txtNumero.Text); // 💥 Crash se non è numero!
lblRisultato.Text = (num * 2).ToString();
}
// ✅ SICURO
private void btnCalcola_Click(object sender, EventArgs e)
{
try
{
double num = Convert.ToDouble(txtNumero.Text);
lblRisultato.Text = (num * 2).ToString();
}
catch (FormatException)
{
lblRisultato.Text = "Inserisci un numero valido!";
}
}
2️⃣ Non Validare la Divisione per Zero
// ❌ ERRORE - Divisione per zero
double risultato = num1 / num2; // 💥 Se num2 = 0, errore!
// ✅ CORRETTO - Controllo prima di dividere
if (num2 != 0)
{
double risultato = num1 / num2;
lblRisultato.Text = risultato.ToString();
}
else
{
lblRisultato.Text = "Errore: divisione per zero!";
}
3️⃣ Confondere = con ==
// ❌ ERRORE - Assegnazione invece di confronto
if (voto = 10) // 💥 ERRORE! Sta assegnando, non confrontando!
{
// Questo codice non compila
}
// ✅ CORRETTO - Confronto
if (voto == 10) // ✅ Confronta se voto è uguale a 10
{
lblGiudizio.Text = "Perfetto!";
}
// Ricorda:
// = → Assegnazione (voto = 10 → assegna 10 a voto)
// == → Confronto (voto == 10 → verifica se voto è 10)
4️⃣ Dimenticare break in switch
// ❌ ERRORE - Manca break
switch (voto)
{
case >= 90:
valutazione = "Eccellente";
// ❌ ERRORE: manca break!
case >= 80:
valutazione = "Molto Buono";
break;
}
// ✅ CORRETTO - break dopo ogni case
switch (voto)
{
case >= 90:
valutazione = "Eccellente";
break; // ✅
case >= 80:
valutazione = "Molto Buono";
break; // ✅
}
🚀 Prossimi Passi: Il Tuo Percorso di Apprendimento
📖 Cosa Farai Nelle Prossime Lezioni
Lezione 8 – Cicli e Iterazioni (TEORIA + GUI)
- 🔄 Ciclo for: Ripetere codice un numero preciso di volte
- ♾️ Ciclo while: Ripetere fino a condizione vera
- ✅ Ciclo do-while: Eseguire almeno una volta
- 📋 Ciclo foreach: Iterare su collezioni (liste, array)
- 🎯 Applicazioni pratiche: Generare tabelle, popolare liste, calcoli ripetuti
Lezione 9 – Array e Liste (TEORIA APPROFONDITA)
- 📊 Array: Collezioni a dimensione fissa
- 📈 List<T>: Collezioni dinamiche (già usate!)
- 🔍 Metodi delle liste: Add, Remove, Contains, Find, Sort
- 🎨 LINQ base: Query su collezioni
- 💡 Quando usare array vs liste
Lezione 10 – Metodi e Funzioni (TEORIA FONDAMENTALE)
- ⚙️ Creare metodi personalizzati: Riutilizzare codice
- 📥 Parametri: Passare dati ai metodi
- 📤 Return: Restituire risultati
- 🔀 Overloading: Metodi con stesso nome, parametri diversi
- 🎯 Refactoring: Migliorare codice esistente
🎯 Il Piano Completo del Corso
Stai seguendo un percorso strutturato che alterna pratica (esercizi con GUI)
e teoria (concetti fondamentali). Dopo le prossime 3 lezioni teoriche,
tornerai a progetti pratici complessi come Gestionale Biblioteca,
Sistema Prenotazioni e altro ancora!
Per consolidare quanto appreso, prova a completare questi esercizi:
- Calcolatrice IMC Migliorata:
Riprendi l’esercizio della Lezione 6 e aggiungi classificazione BMI con colori
(come nell’Esercizio 3 – Valutazione Voto) - Convertitore Multi-Unità:
Estendi il convertitore temperatura aggiungendo conversioni per:
km ↔ miglia, kg ↔ libbre, litri ↔ galloni - Calcolatrice Scientifica Semplice:
Aggiungi alla calcolatrice base (Esercizio 4): potenza (x²), radice quadrata (√),
percentuale (%) - Sistema di Voti:
Crea un’app che permette di inserire più voti in una ListBox, calcola la media
e mostra la valutazione finale (usa Esercizio 3 + Lezione 4)
Lezione 7 – Programmazione ad Eventi: Esercizi Pratici con Windows Forms
Corso C# Completo con Interfaccia Grafica – Da Zero a Esperto
© 2025 Academy PC – Tutti i diritti riservati




