🎯 Progetto Finale: Gestionale Biblioteca
Metti insieme TUTTE le competenze in un’app professionale completa!
🚀 Il Grande Progetto Finale
Hai imparato tutti i controlli di Windows Forms! Ora è il momento di creare
un’applicazione completa e professionale che integra tutto quello
che hai studiato. Questo progetto andrà nel tuo portfolio! 💼✨
Creerai un sistema completo per gestire una biblioteca: catalogo libri,
gestione prestiti, statistiche, ricerca avanzata, salvataggio dati.
Un’applicazione che potresti usare DAVVERO!
- Login con credenziali
- CRUD libri (Create, Read, Update, Delete)
- Gestione prestiti
- Ricerca e filtri
- Salvataggio su file CSV
- TabControl (organizzazione)
- DataGridView (visualizza dati)
- MenuStrip (menu professionale)
- Timer (controlla scadenze)
- ErrorProvider (validazione)
- StatusStrip (info stato)
- Minimo 3 form separati
- Classi custom (Libro, Prestito)
- Validazione input completa
- Gestione errori (try-catch)
- Commenti nel codice
Questo progetto richiede 2-3 settimane di lavoro. Prenditi il tempo necessario
per farlo bene! Puoi procedere a step incrementali.
🏗️ Architettura dell’Applicazione
Scopo: Autenticazione utente
Controlli: TextBox username/password, Button login
Funzionalità: Verifica credenziali, apre FormPrincipale se OK
Scopo: Dashboard principale con 4 schede
Schede:
- 📚 Catalogo: DataGridView con tutti i libri, pulsanti Aggiungi/Modifica/Elimina
- 📤 Prestiti: Gestisci prestiti attivi, controllo scadenze
- 🔍 Ricerca: TextBox ricerca, filtri per categoria/autore
- 📊 Statistiche: Grafici e numeri (libri totali, prestiti attivi, top autori)
Menu: File (Salva, Carica, Esci) | Modifica (Aggiungi Libro) | Aiuto (Info)
Scopo: Aggiungi/Modifica libro
Controlli: TextBox (titolo, autore), NumericUpDown (anno, pagine),
ComboBox (categoria), CheckBox (disponibile)
Validazione: ErrorProvider per tutti i campi
📦 Classi per i Dati
using System;
namespace GestionaleBiblioteca
{
// Classe che rappresenta un libro
public class Libro
{
public int Id { get; set; }
public string Titolo { get; set; }
public string Autore { get; set; }
public int Anno { get; set; }
public int Pagine { get; set; }
public string Categoria { get; set; } // Es: Fantasy, Thriller, Saggio
public bool Disponibile { get; set; }
public DateTime? DataAggiunta { get; set; }
// Proprietà calcolata per CSV
public string CsvFormat =>
$"{Id};{Titolo};{Autore};{Anno};{Pagine};{Categoria};{Disponibile};{DataAggiunta:yyyy-MM-dd}";
// Costruttore vuoto
public Libro()
{
Disponibile = true;
DataAggiunta = DateTime.Now;
}
// Costruttore con parametri
public Libro(int id, string titolo, string autore, int anno, int pagine, string categoria)
{
Id = id;
Titolo = titolo;
Autore = autore;
Anno = anno;
Pagine = pagine;
Categoria = categoria;
Disponibile = true;
DataAggiunta = DateTime.Now;
}
// Parsing da riga CSV
public static Libro FromCsv(string csvLine)
{
string[] parts = csvLine.Split(';');
return new Libro
{
Id = int.Parse(parts[0]),
Titolo = parts[1],
Autore = parts[2],
Anno = int.Parse(parts[3]),
Pagine = int.Parse(parts[4]),
Categoria = parts[5],
Disponibile = bool.Parse(parts[6]),
DataAggiunta = DateTime.Parse(parts[7])
};
}
public override string ToString()
{
return $"{Titolo} - {Autore} ({Anno})";
}
}
}
using System;
namespace GestionaleBiblioteca
{
public class Prestito
{
public int Id { get; set; }
public int IdLibro { get; set; }
public string NomeUtente { get; set; }
public DateTime DataPrestito { get; set; }
public DateTime DataScadenza { get; set; }
public DateTime? DataRestituzione { get; set; }
// Proprietà calcolate
public bool Attivo => DataRestituzione == null;
public bool Scaduto => Attivo && DateTime.Now > DataScadenza;
public int GiorniRimanenti => (DataScadenza - DateTime.Now).Days;
public string CsvFormat =>
$"{Id};{IdLibro};{NomeUtente};{DataPrestito:yyyy-MM-dd};{DataScadenza:yyyy-MM-dd};{DataRestituzione?.ToString("yyyy-MM-dd") ?? ""}";
// Costruttore standard: prestito di 14 giorni
public Prestito(int id, int idLibro, string nomeUtente)
{
Id = id;
IdLibro = idLibro;
NomeUtente = nomeUtente;
DataPrestito = DateTime.Now;
DataScadenza = DateTime.Now.AddDays(14); // 2 settimane
DataRestituzione = null;
}
// Costruttore vuoto
public Prestito() { }
public static Prestito FromCsv(string csvLine)
{
string[] parts = csvLine.Split(';');
return new Prestito
{
Id = int.Parse(parts[0]),
IdLibro = int.Parse(parts[1]),
NomeUtente = parts[2],
DataPrestito = DateTime.Parse(parts[3]),
DataScadenza = DateTime.Parse(parts[4]),
DataRestituzione = string.IsNullOrEmpty(parts[5]) ? null : (DateTime?)DateTime.Parse(parts[5])
};
}
}
}
🔐 Step 1: FormLogin
using System;
using System.Windows.Forms;
namespace GestionaleBiblioteca
{
public partial class FormLogin : Form
{
// Credenziali (in app reale: database!)
private const string USERNAME = "admin";
private const string PASSWORD = "biblioteca";
public FormLogin()
{
InitializeComponent();
txt_password.PasswordChar = '●';
this.AcceptButton = btn_login; // INVIO = click login
// Centra il form
this.StartPosition = FormStartPosition.CenterScreen;
}
private void btn_login_Click(object sender, EventArgs e)
{
string user = txt_username.Text.Trim();
string pass = txt_password.Text;
if (string.IsNullOrEmpty(user) || string.IsNullOrEmpty(pass))
{
lbl_errore.Text = "❌ Compila tutti i campi!";
lbl_errore.Visible = true;
return;
}
if (user == USERNAME && pass == PASSWORD)
{
// ✅ Login OK!
lbl_errore.Visible = false;
// Apri form principale
FormPrincipale principale = new FormPrincipale(user);
principale.Show();
// Nascondi login
this.Hide();
// Quando chiude il principale, chiudi anche questo
principale.FormClosed += (s, args) => this.Close();
}
else
{
// ❌ Errore
lbl_errore.Text = "❌ Credenziali errate!";
lbl_errore.Visible = true;
txt_password.Clear();
txt_password.Focus();
// Animazione shake
AnimazioneErrore();
}
}
private void AnimazioneErrore()
{
int posOriginale = this.Left;
this.Left -= 10;
System.Threading.Thread.Sleep(50);
this.Left = posOriginale + 10;
System.Threading.Thread.Sleep(50);
this.Left = posOriginale;
}
}
}
🏠 Step 2: FormPrincipale (Struttura)
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
namespace GestionaleBiblioteca
{
public partial class FormPrincipale : Form
{
// ═══════════════════════════════════════════
// VARIABILI GLOBALI
// ═══════════════════════════════════════════
private List libri = new List();
private List prestiti = new List();
private string nomeUtente;
private const string FILE_LIBRI = "libri.csv";
private const string FILE_PRESTITI = "prestiti.csv";
// ═══════════════════════════════════════════
// COSTRUTTORE
// ═══════════════════════════════════════════
public FormPrincipale(string utente)
{
InitializeComponent();
this.nomeUtente = utente;
this.Text = $"Gestionale Biblioteca - {utente}";
this.WindowState = FormWindowState.Maximized;
// Setup iniziale
ImpostaDataGridView();
CaricaDati();
AggiornaStatistiche();
// Timer per controllare scadenze ogni minuto
timer_scadenze.Interval = 60000; // 1 minuto
timer_scadenze.Tick += timer_scadenze_Tick;
timer_scadenze.Start();
// StatusBar
toolStripStatusLabel.Text = $"Benvenuto, {utente}! | {libri.Count} libri nel catalogo";
}
// ═══════════════════════════════════════════
// SETUP DATAGRIDVIEW
// ═══════════════════════════════════════════
private void ImpostaDataGridView()
{
dgv_catalogo.Columns.Clear();
dgv_catalogo.Columns.Add("Id", "ID");
dgv_catalogo.Columns.Add("Titolo", "Titolo");
dgv_catalogo.Columns.Add("Autore", "Autore");
dgv_catalogo.Columns.Add("Anno", "Anno");
dgv_catalogo.Columns.Add("Pagine", "Pagine");
dgv_catalogo.Columns.Add("Categoria", "Categoria");
dgv_catalogo.Columns.Add("Disponibile", "Disponibile");
dgv_catalogo.Columns["Id"].Width = 50;
dgv_catalogo.Columns["Titolo"].Width = 250;
dgv_catalogo.Columns["Autore"].Width = 200;
dgv_catalogo.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
dgv_catalogo.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgv_catalogo.MultiSelect = false;
dgv_catalogo.AllowUserToAddRows = false;
// Stesso setup per dgv_prestiti
dgv_prestiti.Columns.Clear();
dgv_prestiti.Columns.Add("Id", "ID");
dgv_prestiti.Columns.Add("Libro", "Libro");
dgv_prestiti.Columns.Add("Utente", "Utente");
dgv_prestiti.Columns.Add("DataPrestito", "Data Prestito");
dgv_prestiti.Columns.Add("Scadenza", "Scadenza");
dgv_prestiti.Columns.Add("GiorniRim", "Giorni Rim.");
dgv_prestiti.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
}
// ═══════════════════════════════════════════
// CARICA DATI DA FILE
// ═══════════════════════════════════════════
private void CaricaDati()
{
try
{
// Carica libri
if (File.Exists(FILE_LIBRI))
{
string[] righe = File.ReadAllLines(FILE_LIBRI);
foreach (string riga in righe)
{
if (!string.IsNullOrWhiteSpace(riga))
{
libri.Add(Libro.FromCsv(riga));
}
}
}
else
{
// Prima volta: aggiungi libri di esempio
AggiungiLibriDiEsempio();
}
// Carica prestiti
if (File.Exists(FILE_PRESTITI))
{
string[] righe = File.ReadAllLines(FILE_PRESTITI);
foreach (string riga in righe)
{
if (!string.IsNullOrWhiteSpace(riga))
{
prestiti.Add(Prestito.FromCsv(riga));
}
}
}
AggiornaDataGridView();
AggiornaPrestiti();
}
catch (Exception ex)
{
MessageBox.Show($"Errore caricamento dati: {ex.Message}", "Errore",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// ═══════════════════════════════════════════
// SALVA DATI SU FILE
// ═══════════════════════════════════════════
private void SalvaDati()
{
try
{
// Salva libri
List righeLibri = new List();
foreach (Libro libro in libri)
{
righeLibri.Add(libro.CsvFormat);
}
File.WriteAllLines(FILE_LIBRI, righeLibri);
// Salva prestiti
List righe Prestiti = new List();
foreach (Prestito p in prestiti)
{
righe Prestiti.Add(p.CsvFormat);
}
File.WriteAllLines(FILE_PRESTITI, righe Prestiti);
toolStripStatusLabel.Text = $"Dati salvati alle {DateTime.Now:HH:mm:ss}";
}
catch (Exception ex)
{
MessageBox.Show($"Errore salvataggio: {ex.Message}", "Errore",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
// ═══════════════════════════════════════════
// AGGIORNA DATAGRIDVIEW CATALOGO
// ═══════════════════════════════════════════
private void AggiornaDataGridView()
{
dgv_catalogo.Rows.Clear();
foreach (Libro libro in libri)
{
int rowIndex = dgv_catalogo.Rows.Add(
libro.Id,
libro.Titolo,
libro.Autore,
libro.Anno,
libro.Pagine,
libro.Categoria,
libro.Disponibile ? "✅ Sì" : "❌ No"
);
// Colora riga se non disponibile
if (!libro.Disponibile)
{
dgv_catalogo.Rows[rowIndex].DefaultCellStyle.BackColor = Color.LightCoral;
}
}
}
// ═══════════════════════════════════════════
// LIBRI DI ESEMPIO (prima volta)
// ═══════════════════════════════════════════
private void AggiungiLibriDiEsempio()
{
libri.Add(new Libro(1, "Il Signore degli Anelli", "J.R.R. Tolkien", 1954, 1178, "Fantasy"));
libri.Add(new Libro(2, "1984", "George Orwell", 1949, 328, "Distopico"));
libri.Add(new Libro(3, "Harry Potter", "J.K. Rowling", 1997, 309, "Fantasy"));
libri.Add(new Libro(4, "Dune", "Frank Herbert", 1965, 688, "Fantascienza"));
libri.Add(new Libro(5, "Il Nome della Rosa", "Umberto Eco", 1980, 503, "Thriller"));
}
}
}
➕ Step 3: CRUD Libri
// ═══════════════════════════════════════════
// PULSANTE: Aggiungi Libro
// ═══════════════════════════════════════════
private void btn_aggiungi_libro_Click(object sender, EventArgs e)
{
FormDettagliLibro formDettagli = new FormDettagliLibro();
if (formDettagli.ShowDialog() == DialogResult.OK)
{
// Nuovo libro da aggiungere
Libro nuovoLibro = formDettagli.LibroCorrente;
// Assegna ID automatico
nuovoLibro.Id = libri.Count > 0 ? libri.Max(l => l.Id) + 1 : 1;
// Aggiungi alla lista
libri.Add(nuovoLibro);
// Aggiorna visualizzazione
AggiornaDataGridView();
AggiornaStatistiche();
// Salva
SalvaDati();
MessageBox.Show($"Libro '{nuovoLibro.Titolo}' aggiunto!", "Successo",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
// ═══════════════════════════════════════════
// PULSANTE: Modifica Libro
// ═══════════════════════════════════════════
private void btn_modifica_libro_Click(object sender, EventArgs e)
{
if (dgv_catalogo.SelectedRows.Count == 0)
{
MessageBox.Show("Seleziona un libro da modificare!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int indice = dgv_catalogo.SelectedRows[0].Index;
Libro libroSelezionato = libri[indice];
FormDettagliLibro formDettagli = new FormDettagliLibro(libroSelezionato);
if (formDettagli.ShowDialog() == DialogResult.OK)
{
// Aggiorna il libro
libri[indice] = formDettagli.LibroCorrente;
// Aggiorna visualizzazione
AggiornaDataGridView();
SalvaDati();
MessageBox.Show("Libro aggiornato!", "Successo",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
// ═══════════════════════════════════════════
// PULSANTE: Elimina Libro
// ═══════════════════════════════════════════
private void btn_elimina_libro_Click(object sender, EventArgs e)
{
if (dgv_catalogo.SelectedRows.Count == 0)
{
MessageBox.Show("Seleziona un libro da eliminare!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int indice = dgv_catalogo.SelectedRows[0].Index;
Libro libro = libri[indice];
// Controlla se è in prestito
bool inPrestito = prestiti.Any(p => p.IdLibro == libro.Id && p.Attivo);
if (inPrestito)
{
MessageBox.Show("Impossibile eliminare: libro in prestito!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
DialogResult ris = MessageBox.Show(
$"Eliminare '{libro.Titolo}'?",
"Conferma",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (ris == DialogResult.Yes)
{
libri.RemoveAt(indice);
AggiornaDataGridView();
AggiornaStatistiche();
SalvaDati();
}
}
// ═══════════════════════════════════════════
// RICERCA LIBRI
// ═══════════════════════════════════════════
private void btn_cerca_Click(object sender, EventArgs e)
{
string termine = txt_ricerca.Text.Trim().ToLower();
if (string.IsNullOrWhiteSpace(termine))
{
// Mostra tutti
AggiornaDataGridView();
return;
}
// Filtra libri
var risultati = libri.Where(l =>
l.Titolo.ToLower().Contains(termine) ||
l.Autore.ToLower().Contains(termine) ||
l.Categoria.ToLower().Contains(termine)
).ToList();
// Mostra risultati
dgv_catalogo.Rows.Clear();
foreach (Libro libro in risultati)
{
dgv_catalogo.Rows.Add(
libro.Id, libro.Titolo, libro.Autore,
libro.Anno, libro.Pagine, libro.Categoria,
libro.Disponibile ? "✅ Sì" : "❌ No"
);
}
toolStripStatusLabel.Text = $"Trovati {risultati.Count} risultati per '{termine}'";
}
📤 Step 4: Gestione Prestiti
// ═══════════════════════════════════════════
// PULSANTE: Nuovo Prestito
// ═══════════════════════════════════════════
private void btn_nuovo_prestito_Click(object sender, EventArgs e)
{
if (dgv_catalogo.SelectedRows.Count == 0)
{
MessageBox.Show("Seleziona un libro!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int indice = dgv_catalogo.SelectedRows[0].Index;
Libro libro = libri[indice];
if (!libro.Disponibile)
{
MessageBox.Show("Libro già in prestito!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// Chiedi nome utente
string nomeUtentePrestito = Microsoft.VisualBasic.Interaction.InputBox(
"Inserisci il nome della persona che prende in prestito il libro:",
"Nuovo Prestito",
""
);
if (string.IsNullOrWhiteSpace(nomeUtentePrestito))
return;
// Crea prestito
int idPrestito = prestiti.Count > 0 ? prestiti.Max(p => p.Id) + 1 : 1;
Prestito prestito = new Prestito(idPrestito, libro.Id, nomeUtentePrestito);
prestiti.Add(prestito);
// Segna libro come non disponibile
libro.Disponibile = false;
// Aggiorna
AggiornaDataGridView();
AggiornaPrestiti();
AggiornaStatistiche();
SalvaDati();
MessageBox.Show(
$"Prestito registrato!\n\n" +
$"Libro: {libro.Titolo}\n" +
$"Utente: {nomeUtentePrestito}\n" +
$"Scadenza: {prestito.DataScadenza:dd/MM/yyyy}",
"Prestito Creato",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
// ═══════════════════════════════════════════
// PULSANTE: Restituisci
// ═══════════════════════════════════════════
private void btn_restituisci_Click(object sender, EventArgs e)
{
if (dgv_prestiti.SelectedRows.Count == 0)
{
MessageBox.Show("Seleziona un prestito!", "Attenzione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
int indicePrestito = dgv_prestiti.SelectedRows[0].Index;
var prestitiAttivi = prestiti.Where(p => p.Attivo).ToList();
Prestito prestito = prestitiAttivi[indicePrestito];
// Registra restituzione
prestito.DataRestituzione = DateTime.Now;
// Trova il libro e rendilo disponibile
Libro libro = libri.FirstOrDefault(l => l.Id == prestito.IdLibro);
if (libro != null)
{
libro.Disponibile = true;
}
// Aggiorna
AggiornaDataGridView();
AggiornaPrestiti();
AggiornaStatistiche();
SalvaDati();
// Verifica se in ritardo
if (prestito.Scaduto)
{
int giorniRitardo = (DateTime.Now - prestito.DataScadenza).Days;
MessageBox.Show(
$"Libro restituito in RITARDO di {giorniRitardo} giorni!",
"Restituzione",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
}
else
{
MessageBox.Show("Libro restituito correttamente!", "Restituzione",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
// ═══════════════════════════════════════════
// AGGIORNA TABELLA PRESTITI
// ═══════════════════════════════════════════
private void AggiornaPrestiti()
{
dgv_prestiti.Rows.Clear();
var prestitiAttivi = prestiti.Where(p => p.Attivo).OrderBy(p => p.DataScadenza);
foreach (Prestito p in prestitiAttivi)
{
Libro libro = libri.FirstOrDefault(l => l.Id == p.IdLibro);
string titoloLibro = libro != null ? libro.Titolo : "Sconosciuto";
int rowIndex = dgv_prestiti.Rows.Add(
p.Id,
titoloLibro,
p.NomeUtente,
p.DataPrestito.ToString("dd/MM/yyyy"),
p.DataScadenza.ToString("dd/MM/yyyy"),
p.GiorniRimanenti
);
// Colora se scaduto
if (p.Scaduto)
{
dgv_prestiti.Rows[rowIndex].DefaultCellStyle.BackColor = Color.LightCoral;
}
else if (p.GiorniRimanenti <= 3)
{
dgv_prestiti.Rows[rowIndex].DefaultCellStyle.BackColor = Color.LightYellow;
}
}
}
// ═══════════════════════════════════════════
// TIMER: Controlla Scadenze
// ═══════════════════════════════════════════
private void timer_scadenze_Tick(object sender, EventArgs e)
{
int prestitiScaduti = prestiti.Count(p => p.Scaduto);
if (prestitiScaduti > 0)
{
toolStripStatusLabel.Text = $"⚠️ {prestitiScaduti} prestiti scaduti!";
toolStripStatusLabel.ForeColor = Color.Red;
}
}
📊 Step 5: Statistiche
// ═══════════════════════════════════════════
// AGGIORNA STATISTICHE
// ═══════════════════════════════════════════
private void AggiornaStatistiche()
{
// Totale libri
lbl_totale_libri.Text = $"Totale Libri: {libri.Count}";
// Libri disponibili
int disponibili = libri.Count(l => l.Disponibile);
lbl_disponibili.Text = $"Disponibili: {disponibili}";
// Prestiti attivi
int prestitiAttivi = prestiti.Count(p => p.Attivo);
lbl_prestiti_attivi.Text = $"Prestiti Attivi: {prestitiAttivi}";
// Autore più presente
if (libri.Count > 0)
{
var autoreTop = libri.GroupBy(l => l.Autore)
.OrderByDescending(g => g.Count())
.First();
lbl_autore_top.Text = $"Autore Top: {autoreTop.Key} ({autoreTop.Count()} libri)";
}
// Categoria più presente
if (libri.Count > 0)
{
var categoriaTop = libri.GroupBy(l => l.Categoria)
.OrderByDescending(g => g.Count())
.First();
lbl_categoria_top.Text = $"Categoria Top: {categoriaTop.Key} ({categoriaTop.Count()} libri)";
}
// Anno medio
if (libri.Count > 0)
{
int annoMedio = (int)libri.Average(l => l.Anno);
lbl_anno_medio.Text = $"Anno Medio: {annoMedio}";
}
}
📕 Step 6: FormDettagliLibro
using System;
using System.Windows.Forms;
namespace GestionaleBiblioteca
{
public partial class FormDettagliLibro : Form
{
public Libro LibroCorrente { get; private set; }
private bool modalitaModifica = false;
// Costruttore per NUOVO libro
public FormDettagliLibro()
{
InitializeComponent();
this.Text = "Nuovo Libro";
LibroCorrente = new Libro();
modalitaModifica = false;
// Popola categorie
cmb_categoria.Items.AddRange(new string[]
{
"Fantasy", "Fantascienza", "Thriller",
"Saggio", "Biografia", "Storia", "Romanzo"
});
cmb_categoria.SelectedIndex = 0;
}
// Costruttore per MODIFICA libro esistente
public FormDettagliLibro(Libro libro) : this()
{
this.Text = "Modifica Libro";
LibroCorrente = libro;
modalitaModifica = true;
// Carica dati esistenti
txt_titolo.Text = libro.Titolo;
txt_autore.Text = libro.Autore;
num_anno.Value = libro.Anno;
num_pagine.Value = libro.Pagine;
cmb_categoria.SelectedItem = libro.Categoria;
}
// ═══════════════════════════════════════════
// PULSANTE: Salva
// ═══════════════════════════════════════════
private void btn_salva_Click(object sender, EventArgs e)
{
// Validazione
bool valido = true;
errorProvider.Clear();
if (string.IsNullOrWhiteSpace(txt_titolo.Text))
{
errorProvider.SetError(txt_titolo, "Titolo obbligatorio");
valido = false;
}
if (string.IsNullOrWhiteSpace(txt_autore.Text))
{
errorProvider.SetError(txt_autore, "Autore obbligatorio");
valido = false;
}
if (num_anno.Value < 1000 || num_anno.Value > DateTime.Now.Year)
{
errorProvider.SetError(num_anno, "Anno non valido");
valido = false;
}
if (num_pagine.Value < 1)
{
errorProvider.SetError(num_pagine, "Pagine devono essere > 0");
valido = false;
}
if (!valido)
{
MessageBox.Show("Correggi gli errori!", "Validazione",
MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
// Salva dati nel libro
LibroCorrente.Titolo = txt_titolo.Text.Trim();
LibroCorrente.Autore = txt_autore.Text.Trim();
LibroCorrente.Anno = (int)num_anno.Value;
LibroCorrente.Pagine = (int)num_pagine.Value;
LibroCorrente.Categoria = cmb_categoria.SelectedItem.ToString();
// Se non in modifica, è disponibile di default
if (!modalitaModifica)
{
LibroCorrente.Disponibile = true;
LibroCorrente.DataAggiunta = DateTime.Now;
}
// Chiudi con OK
this.DialogResult = DialogResult.OK;
this.Close();
}
// ═══════════════════════════════════════════
// PULSANTE: Annulla
// ═══════════════════════════════════════════
private void btn_annulla_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
}
}
✅ Checklist Finale
- ☐ Form login con validazione
- ☐ Apre form principale se credenziali OK
- ☐ Animazione errore
📚 Catalogo Libri:
- ☐ DataGridView con tutti i libri
- ☐ Aggiungi libro (form modale)
- ☐ Modifica libro
- ☐ Elimina libro (con conferma)
- ☐ Colore diverso per libri non disponibili
📤 Prestiti:
- ☐ Crea nuovo prestito
- ☐ Visualizza prestiti attivi
- ☐ Restituisci libro
- ☐ Evidenzia prestiti scaduti
- ☐ Timer controllo scadenze
🔍 Ricerca:
- ☐ Ricerca per titolo/autore/categoria
- ☐ Mostra risultati filtrati
📊 Statistiche:
- ☐ Totale libri
- ☐ Libri disponibili
- ☐ Prestiti attivi
- ☐ Autore/categoria top
💾 Persistenza Dati:
- ☐ Salvataggio su file CSV
- ☐ Caricamento all’avvio
- ☐ Gestione errori (try-catch)
🎨 UI/UX:
- ☐ StatusStrip con info
- ☐ ErrorProvider validazione
- ☐ MenuStrip (File, Modifica, Aiuto)
- ☐ ToolTip su controlli
- ☐ Icone/emoji per rendere accattivante
🚀 Possibili Migliorie (Bonus)
- Stampa Report: Genera PDF o documento Word con statistiche
- Grafici: Usa Chart per mostrare grafici a barre/torta
- Export/Import Excel: Esporta catalogo in Excel
- Foto Copertine: Aggiungi PictureBox per mostrare copertine
- Sistema Voti: Gli utenti possono votare i libri (1-5 stelle)
- Notifiche Email: Invia promemoria scadenze via email
- Multi-Utente: Login diversi con permessi diversi (admin/utente)
- Database Vero: Passa da CSV a SQLite o SQL Server
- Temi: Modalità chiara/scura
- Storico: Salva cronologia di tutti i prestiti passati
Hai completato il percorso Windows Forms! Ora sai creare applicazioni
desktop professionali con interfacce grafiche complete. Questo progetto
dimostra che hai padronanza di:
✅ Gestione eventi
✅ Architettura multi-finestra
✅ Persistenza dati
✅ Validazione professionale
✅ LINQ e collezioni
✅ Problem solving
Sei pronto per il prossimo livello: la programmazione teorica! 🚀