✅ Validazione Avanzata e User Experience
Crea interfacce user-friendly con validazione professionale!
🎯 Cosa Imparerai in Questa Lezione
Hai imparato a creare interfacce e gestire dati. Ora è il momento di renderle
professionali con validazione real-time, messaggi d’errore chiari,
input formattati e feedback visivo immediato! 🚀
Mostra icone di errore accanto ai controlli con problemi.
Feedback visivo professionale!
TextBox con maschera per input formattati: telefono, codice fiscale,
date, codici.
Suggerimenti che appaiono quando passi il mouse sopra un controllo.
Aiuta l’utente!
Barra in fondo alla finestra per mostrare informazioni di stato,
conteggi, messaggi.
- ✅ Dialog e Multi-finestre (Lezione 10)
- ✅ Validazione base (if, string.IsNullOrWhiteSpace)
- ✅ Eventi e metodi
❗ ErrorProvider: Mostra Errori Visivamente
🤔 Cos’è l’ErrorProvider?
Hai presente quando compili un form online e appare un’icona rossa
con un punto esclamativo accanto al campo sbagliato? Quello è un ErrorProvider!
Molto più chiaro di un semplice MessageBox!
- ✅ L’utente vede SUBITO dove ha sbagliato (icona rossa vicino al campo)
- ✅ Può correggere senza chiudere MessageBox fastidiosi
- ✅ Più errori visibili contemporaneamente
- ✅ Passando il mouse sull’icona, appare il messaggio d’errore
- ✅ Look professionale come le app vere!
- Aggiungi un ErrorProvider dalla Toolbox (appare in basso, non è visibile)
- Quando c’è un errore:
errorProvider.SetError(txt_campo, "Messaggio errore") - Quando l’errore è corretto:
errorProvider.SetError(txt_campo, "")
📝 Esercizio 1: Form Registrazione con ErrorProvider
▶ Obiettivo
Crea un form di registrazione utente con validazione real-time.
Ogni campo mostra immediatamente se c’è un errore mentre l’utente digita!
- Label + TextBox:
txt_username(min 5 caratteri) - Label + TextBox:
txt_email(deve contenere @) - Label + TextBox:
txt_password(min 8 caratteri, PasswordChar = ‘●’) - Label + TextBox:
txt_conferma_password(deve essere uguale) - Label + NumericUpDown:
num_eta(Minimum = 13, Maximum = 120) - CheckBox:
chk_termini(Text = “Accetto i termini e condizioni”) - Button:
btn_registrati(Text = “✅ Registrati”) - ErrorProvider:
errorProvider(dalla Toolbox) - ToolTip:
toolTip(dalla Toolbox)
using System;
using System.Text.RegularExpressions;
using System.Windows.Forms;
namespace FormRegistrazione
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Imposta ToolTip per aiutare l'utente
toolTip.SetToolTip(txt_username, "Minimo 5 caratteri, solo lettere e numeri");
toolTip.SetToolTip(txt_email, "Inserisci un'email valida (es: nome@esempio.com)");
toolTip.SetToolTip(txt_password, "Minimo 8 caratteri");
toolTip.SetToolTip(txt_conferma_password, "Deve essere uguale alla password");
toolTip.SetToolTip(num_eta, "Devi avere almeno 13 anni");
// Collega eventi per validazione real-time
txt_username.TextChanged += txt_username_TextChanged;
txt_email.TextChanged += txt_email_TextChanged;
txt_password.TextChanged += txt_password_TextChanged;
txt_conferma_password.TextChanged += txt_conferma_password_TextChanged;
}
// ═══════════════════════════════════════════
// VALIDAZIONE REAL-TIME: Username
// ═══════════════════════════════════════════
private void txt_username_TextChanged(object sender, EventArgs e)
{
string username = txt_username.Text.Trim();
// Valida lunghezza minima
if (username.Length < 5)
{
errorProvider.SetError(txt_username, "Lo username deve essere di almeno 5 caratteri");
txt_username.BackColor = Color.LightPink;
}
// Valida che contenga solo lettere/numeri
else if (!Regex.IsMatch(username, @"^[a-zA-Z0-9]+$"))
{
errorProvider.SetError(txt_username, "Solo lettere e numeri, niente spazi o caratteri speciali");
txt_username.BackColor = Color.LightPink;
}
else
{
// ✅ OK!
errorProvider.SetError(txt_username, "");
txt_username.BackColor = Color.LightGreen;
}
}
// ═══════════════════════════════════════════
// VALIDAZIONE REAL-TIME: Email
// ═══════════════════════════════════════════
private void txt_email_TextChanged(object sender, EventArgs e)
{
string email = txt_email.Text.Trim();
// Regex per validare email (pattern semplice)
string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";
if (string.IsNullOrWhiteSpace(email))
{
errorProvider.SetError(txt_email, "L'email è obbligatoria");
txt_email.BackColor = Color.LightPink;
}
else if (!Regex.IsMatch(email, pattern))
{
errorProvider.SetError(txt_email, "Email non valida (manca @ o dominio)");
txt_email.BackColor = Color.LightPink;
}
else
{
// ✅ OK!
errorProvider.SetError(txt_email, "");
txt_email.BackColor = Color.LightGreen;
}
}
// ═══════════════════════════════════════════
// VALIDAZIONE REAL-TIME: Password
// ═══════════════════════════════════════════
private void txt_password_TextChanged(object sender, EventArgs e)
{
string password = txt_password.Text;
if (password.Length < 8)
{
errorProvider.SetError(txt_password, "La password deve essere di almeno 8 caratteri");
txt_password.BackColor = Color.LightPink;
}
else
{
// ✅ OK!
errorProvider.SetError(txt_password, "");
txt_password.BackColor = Color.LightGreen;
}
// Ricontrolla anche la conferma password
txt_conferma_password_TextChanged(null, null);
}
// ═══════════════════════════════════════════
// VALIDAZIONE REAL-TIME: Conferma Password
// ═══════════════════════════════════════════
private void txt_conferma_password_TextChanged(object sender, EventArgs e)
{
if (txt_conferma_password.Text != txt_password.Text)
{
errorProvider.SetError(txt_conferma_password, "Le password non coincidono");
txt_conferma_password.BackColor = Color.LightPink;
}
else if (!string.IsNullOrEmpty(txt_conferma_password.Text))
{
// ✅ OK!
errorProvider.SetError(txt_conferma_password, "");
txt_conferma_password.BackColor = Color.LightGreen;
}
}
// ═══════════════════════════════════════════
// PULSANTE: Registrati
// ═══════════════════════════════════════════
private void btn_registrati_Click(object sender, EventArgs e)
{
// Controlla che tutti i campi siano validi
bool tuttoValido = true;
// Username
if (txt_username.Text.Trim().Length < 5)
{
tuttoValido = false;
errorProvider.SetError(txt_username, "Username troppo corto");
}
// Email
string emailPattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";
if (!Regex.IsMatch(txt_email.Text.Trim(), emailPattern))
{
tuttoValido = false;
errorProvider.SetError(txt_email, "Email non valida");
}
// Password
if (txt_password.Text.Length < 8)
{
tuttoValido = false;
errorProvider.SetError(txt_password, "Password troppo corta");
}
// Conferma password
if (txt_conferma_password.Text != txt_password.Text)
{
tuttoValido = false;
errorProvider.SetError(txt_conferma_password, "Le password non coincidono");
}
// Età
if (num_eta.Value < 13)
{
tuttoValido = false;
MessageBox.Show("Devi avere almeno 13 anni!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
// Termini
if (!chk_termini.Checked)
{
tuttoValido = false;
MessageBox.Show("Devi accettare i termini e condizioni!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
// Se tutto OK, procedi!
if (tuttoValido)
{
MessageBox.Show(
$"✅ Registrazione completata!\n\n" +
$"Username: {txt_username.Text}\n" +
$"Email: {txt_email.Text}\n" +
$"Età: {num_eta.Value}",
"Successo",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
// Pulisci il form
PulisciForm();
}
else
{
MessageBox.Show("Correggi gli errori evidenziati!", "Errori di validazione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
// ═══════════════════════════════════════════
// HELPER: Pulisci il Form
// ═══════════════════════════════════════════
private void PulisciForm()
{
txt_username.Clear();
txt_email.Clear();
txt_password.Clear();
txt_conferma_password.Clear();
num_eta.Value = 18;
chk_termini.Checked = false;
// Pulisci ErrorProvider
errorProvider.Clear();
// Reset colori
txt_username.BackColor = Color.White;
txt_email.BackColor = Color.White;
txt_password.BackColor = Color.White;
txt_conferma_password.BackColor = Color.White;
}
}
}
- Utente inizia a digitare username: "Mar" → campo rosso + icona errore ❗
- Continua: "Mario" → campo verde ✅ errore sparisce
- Email: "mario" → rosso (manca @)
- Email: "mario@email.it" → verde ✅
- Password: "1234" → rosso (troppo corta)
- Password: "12345678" → verde ✅
- Conferma password: "1234" → rosso (non coincide)
- Conferma password: "12345678" → verde ✅
- Clicca Registrati → se tutto OK: messaggio di successo!
📚 Nuovi Concetti
using System.Text.RegularExpressions;
// Valida email
string pattern = @"^[^@\s]+@[^@\s]+\.[^@\s]+$";
bool valida = Regex.IsMatch("mario@email.it", pattern); // true
// Solo lettere e numeri
bool soloAlfanumerico = Regex.IsMatch("Mario123", @"^[a-zA-Z0-9]+$"); // true
// Numero di telefono italiano (10 cifre)
bool telefono = Regex.IsMatch("3331234567", @"^\d{10}$"); // true
// Mostra errore errorProvider.SetError(txt_campo, "Questo campo è obbligatorio"); // Rimuovi errore errorProvider.SetError(txt_campo, ""); // Pulisci tutti gli errori errorProvider.Clear();
toolTip.SetToolTip(txt_username, "Inserisci il tuo nome utente"); toolTip.SetToolTip(btn_salva, "Clicca per salvare i dati");
🎭 MaskedTextBox: Input Formattati
🤔 Cos'è il MaskedTextBox?
TextBox "intelligente" che guida l'utente nel formato corretto!
Telefono: ___-_______. Data: __/__/____. Codice: ____-____-____.
L'utente può solo digitare nei posti giusti!
// Telefono italiano (10 cifre) Mask = "000-0000000" // 333-1234567 // Data italiana Mask = "00/00/0000" // 15/01/2025 // Codice fiscale italiano Mask = "LLLLLL00L00L000L" // RSSMRA85M15H501Z // CAP (5 cifre) Mask = "00000" // 00100 // Carta di credito Mask = "0000-0000-0000-0000" // 1234-5678-9012-3456 // Ora (HH:MM) Mask = "00:00" // 14:30
- 0 = Cifra obbligatoria (0-9)
- 9 = Cifra opzionale
- L = Lettera obbligatoria (a-z, A-Z)
- ? = Lettera opzionale
- A = Lettera o cifra obbligatoria
- a = Lettera o cifra opzionale
📇 Esercizio 2: Anagrafica Clienti Professionale
▶ Obiettivo
Form anagrafica con MaskedTextBox per telefono, codice fiscale e data di nascita!
- TextBox:
txt_nome - TextBox:
txt_cognome - MaskedTextBox:
mtxt_telefono(Mask = "000-0000000") - TextBox:
txt_email - MaskedTextBox:
mtxt_codice_fiscale(Mask = "LLLLLL00L00L000L") - MaskedTextBox:
mtxt_data_nascita(Mask = "00/00/0000") - Button:
btn_salva - StatusStrip con Label:
toolStripStatusLabel
private void Form1_Load(object sender, EventArgs e)
{
// Imposta maschere
mtxt_telefono.Mask = "000-0000000";
mtxt_codice_fiscale.Mask = "LLLLLL00L00L000L";
mtxt_data_nascita.Mask = "00/00/0000";
// Imposta ToolTip
toolTip.SetToolTip(mtxt_telefono, "Formato: 333-1234567");
toolTip.SetToolTip(mtxt_codice_fiscale, "Es: RSSMRA85M15H501Z");
toolTip.SetToolTip(mtxt_data_nascita, "Formato: GG/MM/AAAA");
// Messaggio iniziale nella StatusBar
toolStripStatusLabel.Text = "Pronto";
}
private void btn_salva_Click(object sender, EventArgs e)
{
// Valida che tutti i campi siano compilati
bool valido = true;
errorProvider.Clear();
if (string.IsNullOrWhiteSpace(txt_nome.Text))
{
errorProvider.SetError(txt_nome, "Nome obbligatorio");
valido = false;
}
if (string.IsNullOrWhiteSpace(txt_cognome.Text))
{
errorProvider.SetError(txt_cognome, "Cognome obbligatorio");
valido = false;
}
// MaskedTextBox: usa MaskCompleted per verificare se è tutto compilato
if (!mtxt_telefono.MaskCompleted)
{
errorProvider.SetError(mtxt_telefono, "Telefono incompleto");
valido = false;
}
if (!mtxt_codice_fiscale.MaskCompleted)
{
errorProvider.SetError(mtxt_codice_fiscale, "Codice fiscale incompleto");
valido = false;
}
if (!mtxt_data_nascita.MaskCompleted)
{
errorProvider.SetError(mtxt_data_nascita, "Data incompleta");
valido = false;
}
// Valida email
if (!txt_email.Text.Contains("@"))
{
errorProvider.SetError(txt_email, "Email non valida");
valido = false;
}
if (valido)
{
// Salva i dati (qui in realtà salveresti su database)
string dati = $"Nome: {txt_nome.Text}\n" +
$"Cognome: {txt_cognome.Text}\n" +
$"Telefono: {mtxt_telefono.Text}\n" +
$"Email: {txt_email.Text}\n" +
$"Codice Fiscale: {mtxt_codice_fiscale.Text}\n" +
$"Data di Nascita: {mtxt_data_nascita.Text}";
MessageBox.Show(dati, "Dati Cliente",
MessageBoxButtons.OK, MessageBoxIcon.Information);
// Aggiorna StatusBar
toolStripStatusLabel.Text = $"Cliente {txt_nome.Text} {txt_cognome.Text} salvato alle {DateTime.Now:HH:mm}";
// Pulisci form
txt_nome.Clear();
txt_cognome.Clear();
txt_email.Clear();
mtxt_telefono.Clear();
mtxt_codice_fiscale.Clear();
mtxt_data_nascita.Clear();
}
else
{
toolStripStatusLabel.Text = "Errore: correggi i campi evidenziati";
}
}
📚 MaskedTextBox - Proprietà
if (mtxt_telefono.MaskCompleted)
{
// Telefono completo!
}
else
{
MessageBox.Show("Completa il numero di telefono!");
}
if (mtxt_codice.MaskFull)
{
// Ogni singolo carattere è stato inserito
}
📊 StatusStrip: Barra di Stato
La StatusStrip è la barra grigia in fondo alle finestre
che mostra info utili: conteggi, stato operazioni, ora ultimo salvataggio, ecc.
- 📄 Editor: "Riga 15, Colonna 23 | 1.245 parole | 7.890 caratteri"
- 💾 App Dati: "Ultimo salvataggio: 14:30 | 47 record"
- 📊 Gestionale: "Totale vendite: €12.450,00 | 25 clienti"
- ✅ Validazione: "Tutti i campi OK" / "⚠️ 3 errori da correggere"
1. Toolbox → StatusStrip → trascina sul form (va automaticamente in fondo)
2. Clicca sulla freccina a destra della StatusStrip
3. Scegli "StatusLabel" per aggiungere una label
4. Properties → (Name) = toolStripStatusLabel
5. Properties → Text = "Pronto"
// Nel codice:
toolStripStatusLabel.Text = "Operazione completata!";
toolStripStatusLabel.Text = $"Record: {conteggio}";
toolStripStatusLabel.Text = $"Salvato: {DateTime.Now:HH:mm:ss}";
📝 Esercizio 3: Mini Editor con Statistiche
▶ Obiettivo
Editor di testo che mostra in tempo reale: parole, caratteri, righe nella StatusBar!
private void txt_editor_TextChanged(object sender, EventArgs e)
{
string testo = txt_editor.Text;
// Conta caratteri
int caratteri = testo.Length;
// Conta parole (split per spazi)
string[] parole = testo.Split(new[] { ' ', '\n', '\r' },
StringSplitOptions.RemoveEmptyEntries);
int conteggioParole = parole.Length;
// Conta righe
int righe = txt_editor.Lines.Length;
// Aggiorna StatusBar
toolStripStatusLabel.Text = $"Caratteri: {caratteri} | Parole: {conteggioParole} | Righe: {righe}";
}
// Bonus: Mostra riga corrente
private void txt_editor_SelectionChanged(object sender, EventArgs e)
{
int riga = txt_editor.GetLineFromCharIndex(txt_editor.SelectionStart) + 1;
int colonna = txt_editor.SelectionStart -
txt_editor.GetFirstCharIndexOfCurrentLine() + 1;
toolStripStatusLabel2.Text = $"Riga {riga}, Colonna {colonna}";
}
🎓 Riepilogo
- Icone errore vicino ai campi
- Validazione real-time
- Feedback visivo professionale
- Input formattati (telefono, CF, data)
- Guida l'utente
- MaskCompleted per validare
- Suggerimenti al passaggio mouse
- Barra stato con info utili
- UX migliorata
- Validazione pattern (email, ecc)
- Regex.IsMatch()
- Pattern comuni pronti
Hai imparato TUTTI i controlli essenziali! È il momento del
PROGETTO FINALE: un gestionale completo che integra tutto! 🎯