Nel mio ultimo (ormai lontano) post relativo ad MCAD,
avevo scritto delle funzioni in grado di leggere e scrivere files XML usando i
metodi messi a disposizione dalla classe DataSet. Usando
ReadXML e WriteXML, siamo riusciti a salvare su disco
l'elenco dei nostri compleanni, così da non dover tutte le volte popolare la
ListBox che abbiamo messo sulla Windows Form principale della nostra
applicazione.
Queste funzionalità hanno reso l'utilizzo della nostra piccola applicazione un po' più semplice
ed intelligente. Riprendiamo il discorso preparandoci ad affrontare al meglio le insidie
di ADO.NET!
Ecco l'interfaccia di Age come si presenta fino ad oggi. Il menù
File incorpora in questo momento quasi tutte le funzioni che ho
descritto dettagliatamente nei post precedenti: anteprima di stampa, imposta
pagina, salvataggio e caricamento su files XML, etc.
Ho intenzione
di aggiungere due menù nuovi di fianco a
File: View e Database. Il primo (mnuView) ci permetterà di giocherellare un
po' con il data-binding di .NET, ma lo vedremo molto, molto
più avanti. Il secondo (mnuDatabase) comprende per adesso un solo
MenuItem chiamato mnuSetup
, che vediamo nel post di oggi.
Che cosa vogliamo fare esattamente?
Beh, innanzitutto
chiariamoci un attimo le idee su quello che vogliamo fare. Dopo aver visto come
lavorare con DataTable e DataSet nei post
precedenti, voglio darmi da fare con qualche database fisico, nello specifico
SQL Server. Ho pensato quindi di dotare la nostra applicazione
Age di una funzione di "esportazione" dei dati verso
una tabella di SQL Server. Quindi, vedremo come lavorare con
SqlConnection e SqlCommand per connetterci
ad un database e per creare da zero una tabella adatta a contenere le
istanze della classe Age che abbiamo inserito nella nostra
ListBox.
E poi? Beh, una volta che la tabella è stata creata,
creeremo una funzione di esportazione che la popoli. Il tutto vedendo le classi
principali per lavorare con ADO.NET, mantenendo uno ed un solo obiettivo
principale: la certificazione MCAD
. Quindi,
useremo DataAdapter, costrutti SELECT, UPDATE ed INSERT INTO per lavorare sui database e
quant'altro. Possiamo procedere? C'è qualcuno che mi ascolta?
Velocemente...aggiungiamo un nuovo Windows
Form
Innanzitutto occorre creare un nuovo WF, che io ho chiamato
frmConnection. Questo WF permetterà all'utente di specificare quale tipo
di database vuole gestire e la stringa di connessione per lavorare su questo database.
Senza dilungarci troppo, ecco l'aspetto della form che ci serve:
Sappiamo come creare Windows Form, vero? Riassumendo: due
GroupBox, due RadioButton, una
TextBox e due Button per chiudere la WF confermando o annullando
le modifiche. Lo so che sembra semplice, eppure qualcosa di interessante da
osservare c'è.
La form dispone di due property
TypeDB e DBConnection, il cui codice
get/set è riportato qui:
public string TypeDB
{
get
{
if(this.optAccess.Checked)
return("ACCESS");
else
return("SQLSERVER");
}
set
{
if(value == "ACCESS")
this.optAccess.Checked = true;
else
this.optSQLServer.Checked = true;
}
}
public string DBConnection
{
get
{
return(this.txtConnection.Text);
}
set
{
this.txtConnection.Text = value;
}
}
Le property sono entrambe di tipo string, e ritornano rispettivamente
il tipo di database e la stringa di
connessione, appunto. Notare che i membri privati delle rispettive property non
esistono, o meglio, esistono eccome
, ma fanno
diretto riferimento alle properties dei controls sulla WF: il membro privato
di DBConnection non è nient'altro che la property Text del control
txtConnection, mentre il membro privato di TypeDB viene ritornato banalmente con
una semplice if
, per capire quale RadioButton è selezionato (può essere "ACCESS"
oppure
"SQLSERVER").
Altra cosa interessante: la classe Button dispone della property
DialogResult . A cosa serve? Quando una WF viene
trattata come una form di dialogo (visualizzandola con il metodo
ShowDialog ), ritorna un valore
dall'enum DialogResult cosicchè possiamo capire in che modo
l'utente ha chiuso la form: ha chiuso cliccando Ok, oppure ha chiuso
cliccando Cancel? La differenza, come potete ben immaginare, è molto molto
diversa. Quindi, per spiegarmi meglio:
// estratto da InitializeComponent
// btnOk e btnCancel
this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
this.btnOk.DialogResult = System.Windows.Forms.DialogResult.OK;
// frmConnection
this.AcceptButton = this.btnOk;
this.CancelButton = this.btnCancel;
Direi che la Form è conclusa qui: manca un grosso dettaglio, ma sarà tema del
prossimo post.
Velocemente...un nuovo handler, ecco a
voi...mnuSetup_Click!
Ho introdotto la struttura della nuova
form. Come fa l'utente ad aprirla? Niente di più semplice! Ricordate il menù
mnuDatabase che ho descritto prima? Questo menù comprende un
solo MenuItem chiamato mnuSetup , il cui codice è il
seguente:
private void mnuSetup_Click(object sender, System.EventArgs e)
{
// Recupero da app.config i valori correnti
// tipo di database e stringa di connessione
System.Configuration.AppSettingsReader read = new System.Configuration.AppSettingsReader();
string TypeDB = (string) read.GetValue("TypeDB", typeof(System.String));
string DBConnection = (string) read.GetValue("DBConnection", typeof(System.String));
DialogResult res;
frmConnection frmNewForm = new frmConnection();
frmNewForm.TypeDB = TypeDB;
frmNewForm.DBConnection = DBConnection;
res = frmNewForm.ShowDialog();
// se l'utente chiude il form cliccando su Ok,
// chiedo se vuole salvare le nuove impostazioni
if (res == DialogResult.OK)
{
// se clicco Ok, ma non ho cambiato nulla,
// evito di chiedere all'utente e di salvare
// su XML, perchè è rimasto tutto invariato
if((frmNewForm.TypeDB != TypeDB) || (frmNewForm.DBConnection != DBConnection))
{
res = MessageBox.Show("Salvare le nuove impostazioni ?", "Conferma!", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (res == DialogResult.Yes)
{
// salvare i nuovi valori da qualche parte
}
}
}
frmNewForm.Dispose();
}
In breve. Usando la classe AppSettingsReader,
leggiamo il file app.config, recuperiamo i valori correnti di
TypeDB e DBConnection. Istanziamo la
form frmNewForm appartenente alla classe frmConnection, e
lo visualizziamo tramite ShowDialog(). Notare che
prima di visualizzarlo imposto le sue property TypeDB e
DBConnection: se guardate il blocco di
codice set delle properties più sopra, vi accorgerete che impostare le properties equivale a
tutti gli effetti impostare le properties del
controls. In questo modo, appena la form apparirà sullo schermo,
mostrerà direttamente i valori correnti.
Torniamo a noi. Il metodo ShowDialog() memorizza in res il
DialogResult. Quindi, if (res ==
DialogResult.OK), vuol dire che l'utente ha chiuso cliccando su
Ok, per cui dobbiamo salvare
i nuovi valori di TypeDB e DBConnection. Giusto per mettere una ciliegina sulla
torta, salvo solamente se l'utente ha effettivamente cambiato qualcosa (questo è
il motivo del secondo if). Dopo un
messaggio di conferma, bisognerebbe salvare i nuovi
valori sul app.config: in realtà questo metodo è
sconsigliato, come mi
rispose Corrado molto, molto tempo fa (in una galassia lontana lontana). Ho comunque omesso il codice, che esula dall'intento di questo
post.
L'obiettivo, che completeremo nel prossimo post, è il seguente. Avete
presente il pulsante Ok sulla nostra nuova Form? Se l'utente
chiude la form cliccando su questo pulsante, significa che desidera confermare
la stringa di connessione, specificando così un server, un database, uno
username ed una password.
Adesso che siamo pronti (finalmente), nel prossimo post parleremo
veramente di ADO.NET.