Press "Enter" to skip to content

Creare un’applicazione WPF per gestire Dati su un database SqlServer – parte 1 Creare l’applicazione

Su richiesta fatta da uno dei frequentatori del blog che state leggendo, proverò a creare nel modo più semplice una applicazione WPF che lavora con i database. 

Essendo una persona pigra ho deciso di utilizzare un database storico come sorgente dati ed iniziare a sviluppare l’interfaccia per modificare una tabella. Il database in questione è il database Pubs che è stato il primo database case study di Sql server (risale credo agli anni ’90). Ne inserirò una copia di backup fatta con SqlServer 2012 per dare una finestra di compatibilità decente a chi scaricherà il progetto.

Cosa gestisce questo database, gestisce una casa editrice (Pubs->Publishers), quindi impiegati, autori, libri e la loro vendita. Partiremo creando il necessario per gestire l’anagrafica degli Autori, poi, se ci saranno richieste per estendere il tutto potremo fare ulteriori cose ed estendere la nostra applicazione.

Considerato che mi è stato chiesto di partire piano e trattare le cose una alla volta, in questo primo articolo creerò il progetto, e spiegherò i primi passi per creare una applicazione reale iniziando a spiegare dove mettere quello che normalmente avremmo messo nel metodo Main dell’applicazione che, nel Template standard di WPF non c’è o meglio c’è ma non si vede.

Ho anche deciso di utilizzare Visual Studio 2017 invece di 2019. Ma sono sicura che non è difficile usare il secondo se vogliamo.

Aperto Visual Studio 2017, usiamo i progetti recenti e selezioniamo WPF App oppure clicchiamo su Nuovo Progetto per andare a creare l’applicazione.

Selezioniamo il tipo di progetto e facciamo le seguenti modifiche:

  • Name = WpfPubs
  • Location = Cartella dei vostri progetti\
  • Solution name = WpfPubs (potete anche cambiarla)
  • Framework = .NET Framework 4.6.2 (può essere anche inferiore o superiore purchè contenga WPF).
  • Create directory for solution = True
  • Create new Git Repository = false (nel mio caso non creo un repository Git ma se lo usate potete crearlo).

Nel nuovo progetto creato, io genero una cartella per mettere la copia di backup del database, per farlo faccio tasto destro sul progetto, Add, New Folder, chiamo la nuova cartella dbbackup.

Una volta aggiunta la cartella, vado ad aggiungere il file del backup del database utilizzando Add Existing Item. 

Il file .bak contenente il backup del database, viene aggiunto al progetto senza alcuna Build Action e non viene copiato nella cartella in cui viene generato l’output di progetto in modo tale che resta solo nel nostro progetto, questo ci permette di aggiungere file accessori ad un progetto che non vengono aggiunti al prodotto. Se invece vogliamo aggiungerlo al Setup dell’applicazione, allora cambiamo i seguenti parametri:

  1. Build Action = Content
  2. Copy to Output Directory = Copy Always

Questo ci permetterà poi di aggiungerlo al setup generato.

Chiedere all’utente la connection string

Ovviamente, in una applicazione vera, non ci sarà solo la Connection String e forse neppure in questa applicazione sarà il solo parametro richiesto, però per cominciare piano, chiederemo all’utente di darci la Connection String e la salveremo su un file in una cartella specifica valida per tutti gli utenti del PC.

Siccome non esiste una InputBox in WPF, creiamo una window apposita per chiedere la connection string, ma per preparare la strada a cose che faremo in seguito, non la creiamo sulla root del progetto ma la mettiamo su una sottocartella che chiamiamo Windows.

Usiamo quindi Add New Item per creare una nuova Window.

Creiamo quindi la nuova Window che chiamiamo ConfigWindow e in questa Window andremo ad inserire per ora solo la stringa di connessione, poi vedremo se ci servirà altro.

Adesso che abbiamo la Window però dobbiamo sapere dove chiamarla. Ovviamente, avremo bisogno di chiedere la Stringa di connessione prima di qualsiasi cosa, pertanto anche prima di chiamare la MainWindow. Questo comporta alcune modifiche al funzionamento impostato come base dal Template standard di WPF. Pertanto vediamo cosa dobbiamo modificare.

Prima di tutto, se andate a guardare i file creati dal Template ovvero App.Xaml e MainWindow.Xaml ed il loro codice correlato in App.xaml.cs e MainWindow.xaml.cs, non troverete il metodo Main.

Questo perché WPF lo maschera, in realtà viene creato dal compilatore XAML. Però ovviamente ci viene fornito un luogo ove inserire quello che solitamente veniva aggunto nel program.cs all’interno del metodo Main.

Chiedo scusa per la trasparenza ma intellisense rende trasparente il tooltip quando premiamo i tasti per lo screenshot. La classe Application da cui viene derivato App, possiede una serie di Eventi di cui possiamo fare l’Override per inserire il nostro codice all’interno degli eventi primari collegati all’applicazione. Nel nostro caso, per inserire quello che normalmente mettiamo nel Main usiamo l’evento OnStartup. Quando in Visual Studio creiamo il metodo ci viene automaticamente scritto questo codice:

protected override void OnStartup(StartupEventArgs e)
{
	base.OnStartup(e);
}

Non tanto ovviamente, ricordate che la chiamata base.OnStartup non va eliminata perché esegue tutto il codice di Startup standard dell’applicazione, quindi tutto quello che sta dentro allo XAML di App.xaml e quello che prevede la classe Application, se lo togliamo potremo avere effetti indesiderati.

Invece dobbiamo andare nell’App.xaml e dobbiamo togliere la chiamata automatica alla MainWindow, la ripristineremo nel codice al termine delle chiamate necessarie allo startup dell’applicazione.

<Application x:Class="WpfPubs.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:WpfPubs">
    <Application.Resources>
         
    </Application.Resources>
</Application>

App.xaml divverrà quindi quello che ho scritto qui sopra. E ora andiamo a scrivere il nostro evento OnStartup.

protected override void OnStartup(StartupEventArgs e)
{
	this.ShutdownMode = System.Windows.ShutdownMode.OnLastWindowClose;
	base.OnStartup(e);
 

	List<stringcommandLineArguments = null;
	if (e.Args != null && e.Args.Length > 0)
	{
		commandLineArguments = new List<string>(e.Args);
	}
 
	bool existConfigArgument = commandLineArguments != null &&
		commandLineArguments.FirstOrDefault(x => x.ToLower() == "-config"!= null;
 
	if (!File.Exists(ConfigFullName|| existConfigArgument)
	{
		if (!OpenConfigWindow())
		{
			MessageBox.Show("Si è verificato un errore nella gestione della configurazione del programma non è possibile eseguirlo.");
			Shutdown();
			return;
		}
	}
	else
	{
		CnString = File.ReadAllText(ConfigFullName);
	}
	OpenMainWindow();
}

Commenterò il metodo OnStartup e mi fermerò per questo articolo a cui non allegherò neppure il codice, invitandovi a provare a generare il progetto e creare i metodi vuoti che ho inserito nel metodo OnStartup, nel prossimo articolo andremo a riempirli creando la Window per richiedere la connection string e aprendo poi la Main Window.

this.ShutdownMode = System.Windows.ShutdownMode.OnLastWindowClose;
base.OnStartup(e);

La prima riga del nostro OnStartup è stata inserita per mostrare come si può cambiare il modo in cui una applicazione WPF si chiude, questo ci da la libertà di decidere in base alle necessità se l’applicazione si chiude in uno dei seguenti modi:

  1. OnMainWindowClose – quando viene chiusa la MainWindow (Per una MDI per esempio).
  2. OnLastWindowClose – Quando si chiude l’ultima finestra (pensate a Word o Excel).
  3. OnExplicitShutdown – Siamo noi a decidere quando l’applicazione si chiude e come.

La seconda cosa che facciamo è eseguire le operazioni di startup della classe base (Application).

List<stringcommandLineArguments = null;
if (e.Args != null && e.Args.Length > 0)
{
	commandLineArguments = new List<string>(e.Args);
}

L’evento di Startup è anche quello che ci trasmette gli eventuali parametri da linea di comando (quelli che nelle applicazioni con il Main erano gli argomenti del metodo stesso) questi argomenti sono forniti nell’array di stringhe Args contenuto nell’Event Argument di OnStartup. Come vedete io li metto in un Array di stringhe.

bool existConfigArgument = commandLineArguments != null &&
	commandLineArguments.FirstOrDefault(x => x.ToLower() == "-config"!= null;

Dopo aver elaborato i Command Line Arguments verifico se esistono e se uno di essi contiene la stringa “-config”, in questo caso, aprirò la finestra di configurazione prima di qualsiasi altra cosa. Ci serve solitamente se ci sono stati problemi sul file di configurazione che devono essere corretti.

if (!File.Exists(ConfigFullName|| existConfigArgument)
{
	if (!OpenConfigWindow())
	{
		MessageBox.Show("Si è verificato un errore nella gestione della configurazione del programma non è possibile eseguirlo.");
		Shutdown();
		return;
	}
}
else
{
	CnString = File.ReadAllText(ConfigFullName);
}

A questo punto, se il file di configurazione non esiste o se è stato richiesto di aprire la window di configurazione, viene aperta la finestra di configurazione e in caso di errore, il programma viene chiuso. Se il file di configurazione è stato trovato, leggiamo il suo contenuto ovvero la stringa di connessione.

Ci fermiamo qui, vi invito a provare a generare il progetto e fare tutte le modifiche fatte fino qui, se avete domande o in caso troviate degli errori usate la bustina in cima alla pagina per mandarmi un messaggio.

La prossima volta, acquisiremo la stringa di connessione.