Press "Enter" to skip to content

Creare un’applicazione WPF per gestire Dati su un database SqlServer – parte 2 La connection String

La prima cosa da fare prima di aprire la Main Window è verificare e chiedere all’utente i parametri di configurazione. Nel nostro caso, la stringa di connessione a Database. Creiamo una Window per acquisirla e salvarla su una cartella dell’Utente.

Per fare questo, e per preparare la strada ad alcune modifiche successive, creo una cartella all’interno del progetto.

Per creare la cartella mi posiziono sul nodo di progetto (WpfPubs) nel solution explorer e seleziono l’opzione Add -> New Folder per generare la cartella.

MI viene generata una cartella NewFolder1 che provvederò a rinominare come segue.

Chiamiamo la cartella Windows perché vi metteremo tutte le window di questa applicazione, più avanti sposteremo li anche la MainWindow così vi mostro come si fa a spostare una finestra e sopravvivere.

Ora ci posizioniamo sul nodo della cartella Windows del solution explorer e con il tasto destro, sul menu contestuale scegliamo Add -> New Item… Per aggiungere la finestra di configurazione in cui chiederemo all’utente di darci la stringa di connessione a database.

Per creare la window eseguiamo i 4 step sopra indicati:

  1. Selezioniamo WPF nella lista dei template di oggetto
  2. Selezioniamo Window (WPF)
  3. Chiamiamo la nuova finestra ConfigWindow.xaml
  4. Premiamo il tasto Add

E la window verrà creata nella nuova cartella Windows.

La nuova finestra è stata generata, quindi andiamo ad inserire il necessario per chiedere la stringa di connessione a SqlServer al nostro utente.

<Window x:Class="WpfPubs.Windows.ConfigWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfPubs.Windows"
        mc:Ignorable="d"
        Title="ConfigWindow" Height="450" Width="800">
    <Grid>
 
 
	</Grid>
</Window>

La window appena creata è molto spoglia, andiamo ad aggiungere il necessario per richiedere la connection string per la nostra applicazione.

<Window x:Class="WpfPubs.Windows.ConfigWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfPubs.Windows"
        mc:Ignorable="d"
		ContentRendered="ConfigWindow_ContentRendered"
        Title="Gestione Parametri di configurazione applicativi" Height="240" Width="800">

Per prima cosa modifichiamo il Tag Window nel seguente modo:

  • Scriviamo un titolo che spiega cosa gestisce la window
  • Aggiungiamo un event handler per l’evento ContentRendered, questo evento viene scatenato dopo che la finestra è stata aperta e tutti i componenti sono istanziati, qui si pone solitamente il codice che carica i dati, nel nostro caso andremo a leggere il file di configurazione e verificheremo che siano stati forniti i dati necessari alla finestra per funzionare. Vedremo il codice una volta inseriti tutti i componenti nella window.
<Grid.RowDefinitions>
	<RowDefinition Height="Auto"/>
	<RowDefinition Height="Auto"/>
	<RowDefinition Height="Auto"/>
	<RowDefinition Height="*"/>
	<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>

Prima di tutto creo nella grid base alcune righe dove metterò i vari componenti ovvero una serie di testi con le istruzioni e la textbox ove inserire la stringa di connessione.

<TextBlock Grid.Row="0"
	Margin="4,2,4,2"
	HorizontalAlignment="Left"
	FontSize="16"
	Foreground="Navy"
	FontWeight="Bold"
	Text="Stringa di connessione a database"/>

Inserisco la prima stringa nella riga 0 della Grid appena generata, voglio sia l’istruzione principale per l’utente e la voglio rendere più visibile, quindi come versione beginner assegno direttamente le property relative alla font al controllo TextBlock in uno degli articoli successivi alla conclusione della serie base di cui questo articolo è parte, parleremo di stili e genereremo degli stili che si occuperanno di dare l’aspetto ai controlli, invece di dover scrivere l’aspetto per tutti i controlli a mano. Gli attributi che ho settato sono:

  • Margin = Margine attorno al Textblock rispettivamente Left=4, Top=2, Right=4, Bottom=2
  • HorizontalAlignment = Allineamento orizzontale del controllo a sinistra
  • FontSize = Dimensione del carattere 16
  • Foreground = Colore del testo Blu Navy
  • FontWeight = Grossezza del testo Bold

Infine ovviamente il testo dell’etichetta.

<TextBlock Grid.Row="1"
	Margin="4,8,4,2"
	HorizontalAlignment="Left"
	Foreground="DarkGreen"
	Text="Es. Trusted connection: Data Source=NomeServer;Integrated security=SSPI;Persist Security Info=True;Initial Catalog=NomeDatabase;"/>
<TextBlock Grid.Row="2"
	Margin="4,8,4,2"
	HorizontalAlignment="Left"
	Foreground="DarkCyan"
	TextWrapping="Wrap"
	Text="Es. Sql Connection: Data Source=NomeServer; User ID=NomeUtente;Password=LaPasswordUtente;Persist Security Info=True;Initial Catalog=NomeDatabase;"/>

Sulla seconda e terza riga, inserisco due etichette con gli esempi di come scrivere la connection string, nel primo caso in modalità “Trusted connection”, nel secondo in modalità SQL Connection con username e password.

Per chi non fosse esperto in SQL Server, la Trusted Connection si effettua quando l’accesso ad un database viene concesso ad un gruppo o ad un utente windows e quindi non c’è bisogno di user name e password per la connessione. 

Tornando alle label, le ho fatte di due colori diversi per evidenziarle all’utente.

 

<TextBox Grid.Row="3"
	Margin="4,2,4,2"
	HorizontalAlignment="Stretch"
	VerticalAlignment="Top"
	AcceptsReturn="False"
	AcceptsTab="False"
	HorizontalContentAlignment="Left"
	VerticalContentAlignment="Center"
	MinHeight="36"
	Text="{Binding CnString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

 

Aggiungo ora la textbox che viene collegata in Binding alla property CnString che definiremo nel codice della Window, questa property poi sarà scritta e riletta da un file di configurazione.

<StackPanel Grid.Row="4"
	Margin="4"
	Orientation="Horizontal"
	FlowDirection="RightToLeft">
... qui ci vanno i button ...
</StackPanel>

Nell’ultima riga, aggiungo uno stack panel in cui metteremo tutti i Button di comando. Li descriverò uno per uno.

<Button
	Margin="4,2,4,2"
	Padding="10,4,10,4"
	Click="Ok_Click">
	<TextBlock Margin="4,2,4,2"
		TextWrapping="NoWrap"
		Text="Ok"/>
</Button>

Il primo bottone è l’OK per confermare e salvare la stringa di connessione.

<Button
	Margin="4,2,4,2"
	Padding="10,4,10,4"
	Click="Cancel_Click">
	<TextBlock Margin="4,2,4,2"
		TextWrapping="NoWrap"	
		Text="Annulla"/>
</Button>

Il secondo bottone è l’annulla modifiche.

<Button
	Margin="50,2,4,2"
	Padding="10,4,10,4"
	Click="Test_Click">
	<TextBlock Margin="4,2,4,2"
		TextWrapping="NoWrap"				
		Text="Test Connessione"/>
</Button>

Infine un bottone per testare se la stringa di connessione è OK.

Una volta inseriti i 3 Button è necessario creare gli Event Handler per gli eventi Click, se infatti non li generiamo la compilazione darà errore indicandoci che mancano tali event handler. Per creare un event Handler, basta posizionare il cursore sopra al nome dell’evento e premere Tasto destro, scegliendo Go to Definition sul menu contestuale.

Selezionando l’opzione su indicata verrà creato per noi il codice dell’Event Handler se non esiste già e verremo portati all’interno di tale codice.

private void Test_Click(object senderRoutedEventArgs e)
{
	try
	{
		
... qui scriveremo il codice dell'Event Handler
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

Visto che ci siamo, scriviamo il codice necessario a testare se la connection string funziona, è un codice semplice e diretto, ma non ho mai trovato qualcuno che suggerisse qualcosa di diverso.

private void Test_Click(object senderRoutedEventArgs e)
{
	try
	{
		
		using (SqlConnection cn = new SqlConnection(CnString))
		{
			cn.Open();
			cn.Close();
		}
		MessageBox.Show("Connessione OK");
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

Per testare se la stringa di connessione funziona, usiamo una SqlConnection in cui poniamo la nostra stringa di connessione e poi apriamo e chiudiamo la connessione al database. Se la stringa di connessione fosse errata, il server non fosse attivo, il database non esistesse, .Net prova a connettersi al database indicato, se non esiste il database o il server o se i dati dell’utente sono errati, verrà restituita una eccezione e quindi potremo dare il messaggio all’utente affinché controlli la stringa di connessione e riprovi prima di salvare.

private void Ok_Click(object senderRoutedEventArgs e)
{
	try
	{
		File.WriteAllText(ConfigFullNameCnString);
		if (System.Windows.Interop
			.ComponentDispatcher.IsThreadModal)
		{
			DialogResult = true;
		}
		Close();
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

Il bottone OK, scrive il testo della connection string su file e restituisce un messaggio di “ok” al chiamante.Questo è un articolo dedicato ai principianti, però ho introdotto un pezzetto di codice in più che è interessante anche per i Non principianti. ed è l’istruzione if(System.Windows.Interop…

A cosa serve e perché l’ho inserita. Come spero tutti coloro che leggono sappiano, ci sono 2 modi per chiamare una Window, usare il metodo Show() oppure il metodo ShowDialog(). Il primo metodo istanzia e rende visibile la finestra, ma permette ad un eventuale finestra chiamante di continuare il proprio lavoro e funzionare anche mentre la seconda finestra è aperta. Il secondo metodo invece apre una finestra cosiddetta “Modale” che impedisce a qualsiasi altra finestra dell’applicazione qualsiasi operatività fino a quando la “Modale” non viene chiusa. Tipicamente una finestra modale si usa per chiedere all’utente una conferma a qualcosa o un dato puntuale (nel nostro caso la stringa di connessione) prima di proseguire con l’esecuzione del codice. La finestra Modale più usata è solitamente la MessageBox che permette dare informazioni all’utente oppure di chiedere risposte di tipo “Si, No” o “Conferma, Annulla”.

La nostra Window di Configurazione sarà aperta in 2 diversi luoghi all’interno della nostra applicazione, allo Startup della stessa nel caso non esistesse il file contenente la stringa di connessione o se tale stringa di connessione non  fosse corretta, in questo caso, sarà aperta come finestra Modale, perché fino a che la stringa di connessione non sarà corretta l’applicazione non potrà proseguire.

Ma potremo avere la necessità di modificare una stringa di connessione funzionante (magari per cambiare il database) e per fare questo prevederò un pulsante sull’interfaccia principale dell’applicazione. In questo caso, potremmo aprire la finestra sia come Modale che come normale finestra applicativa.

Da qui la necessità del controllo che ho inserito prima di impostare il parametro DialogResult.

if (System.Windows.Interop.ComponentDispatcher.IsThreadModal)
{
	DialogResult = true;
}

Il codice qui sopra scritto, verifica se la Window è aperta come “Modale” e prima di chiudersi aggiorna la property DialogResult, se la finestra non fosse stata aperta come Modale, la riga darebbe un errore perché la property è usabile solo nel caso di apertura Modale. 

Per i principianti, a cosa serve settare DialogResult a true o false? Serve perché questo valore viene restituito dalla chiamata ShowDialog() al codice chiamante e può essere utilizzato per decidere se proseguire l’esecuzione o se agire in modo diverso. Lo vedremo non appena implementeremo il “Main” dell’applicazione.

private void Cancel_Click(object senderRoutedEventArgs e)
{
	try
	{
		if (System.Windows.Interop.ComponentDispatcher.IsThreadModal)
		{
			DialogResult = false;
		}
		Close();
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

L’ultimo dei tre button, permette di uscire dalla Window e annullare qualsiasi modifica fatta alla stringa di connessione a Database, ovviamente se la stringa è errata, questo potrebbe portare ad un errore, quindi vedremo come gestirlo nei successivi articoli.

L’ultimo pezzetto di codice che inserisco è il codice dell’evento ContentRendered della Window, solitamente io uso questo evento, che si scatena dopo che la Window è stata caricata e resa visibile per controllare che tutti i parametri necessari al suo funzionamento siano corretti e per caricare eventuali dati che la window gestisce.

 

private void ConfigWindow_ContentRendered(object senderEventArgs e)
{
	try
	{
		if (ConfigFullName == null || ConfigFullName.Trim().Length == 0)
		{
			MessageBox.Show("ATTENZIONE! i parametri funzionali della window non sono stati inizializzati chiamare il metodo Init prima dello Show.");
			Close();
		}
		if (File.Exists(ConfigFullName))
		{
			CnString = File.ReadAllText(ConfigFullName);
		}
	}
	catch (Exception ex)
	{
		MessageBox.Show(ex.Message);
	}
}

In questo event handler, come potete vedere, per prima cosa verifico se è stato passato un nome per il file di configurazione, se così non fosse c’è un errore da parte del programmatore, controllare che i parametri fondamentali per far funzionare una Window siano stati inizializzati e dare un messaggio di errore a noi stessi ci risparmierà un po’ di lavoro in Debug. e sarà molto utile se, lavorando in gruppo con altri programmatori produrremo codice che altri dovranno usare, segnalare quali parametri ci servono per far funzionare una window correttamente è buona norma per evitare di sprecare tempo a cercare problemi che non sono tali.

Per ora mi fermo qui e anche in questo secondo articolo non posto il progetto perché non è ancora funzionante. Nel prossimo articolo, termineremo il “Main” dell’applicazione ed apriremo la finestra principale dopo esserci assicurati che la stringa di connessione al database sia corretta.