Vai al contenuto

Primi esercizi

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

  • βœ… Visual Studio e primi passi: progetto Windows Forms, Button, evento Click, MessageBox
  • βœ… Variabili e operatori: int, double, string, bool, calcoli e conversioni
  • βœ… Decisioni: if, else if, else, switch, TryParse e try/catch
  • βœ… TextBox e Label: leggere l'input dell'utente e mostrare i risultati

🎯 Focus di Questa Lezione

Ora Γ¨ tempo di mettere insieme tutto questo 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

πŸ’‘ PerchΓ© Questa Lezione Γ¨ Importante

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:

  1. File β†’ Nuovo β†’ Progetto
  2. Seleziona "Applicazione Windows Forms (.NET Framework)"
  3. Nome: CalcolatoriceSomma
  4. 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.

  1. Gestione dell'Evento Click del Pulsante

Quando l'utente clicca sul pulsante "Calcola Somma", dobbiamo:

  1. Verificare che entrambi i campi siano compilati
  2. Convertire i testi in numeri
  3. Calcolare la somma
  4. Mostrare il risultato
  5. Gestire eventuali errori

Form1.cs - Evento Click

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.

  1. 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!

Form1.cs - Eventi TextChanged

// ═══════════════════════════════════════════════════════
// 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:

  1. Seleziona txtNumero1 nel Designer
  2. Premi F4 per aprire le ProprietΓ 
  3. Clicca sull'icona del fulmine ⚑ (Eventi)
  4. Trova TextChanged e fai doppio click
  5. Visual Studio crea automaticamente il metodo txtNumero1_TextChanged
  6. Ripeti per txtNumero2

🎬 Flusso di Esecuzione:

  1. Utente apre l'app β†’ btnCalcola.Enabled = false (disabilitato)
  2. Utente scrive "12" in txtNumero1 β†’ Evento txtNumero1_TextChanged
  3. Chiama ValidaInput() β†’ txtNumero2 Γ¨ vuoto β†’ return false
  4. btnCalcola.Enabled = false β†’ Pulsante ancora disabilitato
  5. Utente scrive "8" in txtNumero2 β†’ Evento txtNumero2_TextChanged
  6. Chiama ValidaInput() β†’ Entrambi sono numeri validi β†’ return true
  7. btnCalcola.Enabled = true β†’ βœ… Pulsante si abilita!
  8. Utente clicca "Calcola Somma" β†’ Evento btnCalcola_Click
  9. Calcola 12 + 8 = 20 β†’ Mostra "Risultato: 20" (verde)

Metodi e Concetti - Esercizio 1

string.IsNullOrEmpty(string)

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 Γ¨ null
  • string.IsNullOrEmpty(txt.Text) β†’ Gestisce sia null che ""

Convert.ToDouble(string)

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

.ToString()

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

try-catch (Gestione Eccezioni)

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
}

Control.Enabled (proprietΓ )

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;

Operatore || (OR Logico)

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-else per eseguire codice condizionalmente
  • βœ… Convert.ToInt32() per numeri interi
  • βœ… Cambiare colore del testo con ForeColor
  • βœ… Evento KeyPress per 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
  1. Codice Completo con Spiegazione

Form1.cs - Verifica Pari/Dispari

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.

  1. 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".

Form1.cs - Evento KeyPress

// ═══════════════════════════════════════════════════════
// 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:

  1. Seleziona txtNumero nel Designer
  2. F4 β†’ Fulmine ⚑ β†’ Trova KeyPress
  3. Fai doppio click su KeyPress
  4. Scrivi il codice sopra nel metodo generato

🎬 Cosa Succede con KeyPress:

  1. Utente prova a scrivere "a" β†’ KeyPress si attiva
  2. char.IsDigit('a') = false
  3. char.IsControl('a') = false
  4. 'a' == '-' = false
  5. e.Handled = true β†’ ❌ "a" viene bloccato!
  6. Utente prova a scrivere "5" β†’ char.IsDigit('5') = true
  7. Tasto permesso β†’ βœ… "5" viene inserito in txtNumero

Nuovi Metodi e Concetti - Esercizio 2

Convert.ToInt32(string)

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)

Operatore % (Modulo)

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;

if-else (Struttura Condizionale)

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";
}

Control.ForeColor (proprietΓ )

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;
}

char.IsDigit() / char.IsControl()

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
    }
}

string.IndexOf(char)

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
}

TextBox.SelectionStart (proprietΓ )

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 switch per 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
  1. Codice con Switch Statement

Form1.cs - Valutazione con Switch

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 Compatibile (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;
}
  1. Validazione Avanzata con KeyPress

Form1.cs - KeyPress per Voto

// ═══════════════════════════════════════════════════════
// 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

switch Statement

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 programma NON si compila (errore CS0163):
// in C#, a differenza di C e Java, un case non puΓ² "cadere" nel successivo

Pattern Matching con Range (C# 9.0+)

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;
}

⚠️ Compatibilità: Questa sintassi richiede C# 9.0+ (Visual Studio 2019 16.8 o successivo). Se non disponibile, usa if-else.

Operatore && (AND Logico)

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
}

break Statement

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 DI COMPILAZIONE: manca break!
        // In C# il codice NON puΓ² "cadere" nel case successivo:
        // Visual Studio sottolinea in rosso e il programma non parte
    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
  1. Codice Completo della Calcolatrice

Form1.cs - Calcolatrice Completa

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.

  1. 🎬 Flusso di Esecuzione Completo

Scenario: Calcolare 10 + 5

  1. Avvio applicazione:
    • Form1_Load si attiva
    • Tutti i pulsanti vengono disabilitati (Enabled = false)
  2. Utente scrive "10" in txtNumero1:
    • Evento txtNumero1_TextChanged
    • Chiama ValidaInput() β†’ txtNumero2 Γ¨ vuoto β†’ return false
    • AbilitaPulsanti(false) β†’ Pulsanti ancora disabilitati
  3. Utente scrive "5" in txtNumero2:
    • Evento txtNumero2_TextChanged
    • Chiama ValidaInput() β†’ Entrambi sono numeri β†’ return true
    • AbilitaPulsanti(true) β†’ βœ… Pulsanti si abilitano!
  4. 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"

Operatori Aritmetici in C#

Operatore + (Somma)

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"

Operatore - (Sottrazione)

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

Operatore * (Moltiplicazione)

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

Operatore / (Divisione)

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!
}

Precedenza Operatori

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.

  1. Codice Completo del Convertitore

Form1.cs - Convertitore Temperatura

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
  1. 🎬 Flusso di Esecuzione: Convertire 0°C

  2. Avvio applicazione:

    • rbCelsius Γ¨ selezionato di default (Checked = true)
    • lblTitolo: "πŸ”₯ Converti da Celsius a Fahrenheit"
  3. Utente scrive "0" in txtTemperatura

  4. 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)
  5. Utente clicca su rbFahrenheit:

    • Evento rbFahrenheit_CheckedChanged
    • rbCelsius automaticamente diventa Checked = false
    • Chiama AggiornaInterfaccia()
    • lblTitolo: "❄️ Converti da Fahrenheit a Celsius"
    • lblRisultato: "" (pulito)
  6. 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

RadioButton

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
}

RadioButton.Checked (proprietΓ )

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
}

Evento CheckedChanged

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
    }
}

Formattazione :F1

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!)

String Interpolation $"..."

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";

Precedenza con Parentesi

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-else per decisioni binarie
  • if-else if-else per condizioni multiple
  • switch per valutazioni discrete
  • Pattern matching con range (C# 9.0+)

πŸ”„ Conversioni di Tipo

  • Convert.ToDouble() per decimali
  • Convert.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
  • .Checked per 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-catch o TryParse)
  • βœ… È 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 Nella Prossima Lezione

Ripetere e riutilizzare: cicli e metodi

  • πŸ”„ Ciclo for: ripetere codice un numero preciso di volte (tabelline, somme)
  • ♾️ while e do-while: ripetere finchΓ© serve
  • 🧠 Campi del form: ricordare un valore tra un clic e l'altro
  • βš™οΈ Metodi tuoi: parametri e return, per non copiare lo stesso codice in piΓΉ bottoni

🎯 Il Piano Completo del Corso

Nelle prossime lezioni passerai da un valore alla volta a elenchi di dati (ListBox, ComboBox, List), poi agli oggetti (Parco Auto) fino al progetto finale Gestionale Biblioteca. Per la teoria di cicli, array e metodi trovi le lezioni del percorso C# – il linguaggio.

πŸ’ͺ Esercitazione Prima della Prossima Lezione

Per consolidare quanto appreso, prova a completare questi esercizi:

  1. Calcolatrice IMC Migliorata: Riprendi la calcolatrice IMC e aggiungi classificazione BMI con colori (come nell'Esercizio 3 - Valutazione Voto)
  2. Convertitore Multi-UnitΓ : Estendi il convertitore temperatura aggiungendo conversioni per: km ↔ miglia, kg ↔ libbre, litri ↔ galloni
  3. Calcolatrice Scientifica Semplice: Aggiungi alla calcolatrice base (Esercizio 4): potenza (x²), radice quadrata (√), percentuale (%)
  4. Sistema di Voti: Crea un'app che permette di inserire piΓΉ voti in una ListBox, calcola la media e mostra la valutazione finale (usa l'Esercizio 3 + la ListBox, che vedrai tra due lezioni)

πŸ“š Teoria collegata (percorso C# – il linguaggio, esempi in console): Strutture di controllo e Gestione delle eccezioni.