Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1909, comments - 2047, trackbacks - 352

My Links

News

Your host

This is me! Questo spazio è dedicato a Microsoft® .NET®, di cui sono molto appassionato :-)

Cookie e Privacy

Microsoft MVP

My MVP Profile

Microsoft Certified Professional

Microsoft Specialist

Xamarin Certified Mobile Developer

Il mio libro su VB 2015!

Pre-ordina il mio libro su VB 2015 Pre-ordina il mio libro "Visual Basic 2015 Unleashed". Clicca sulla copertina per informazioni!

Il mio libro su WPF 4.5.1!

Clicca sulla copertina per informazioni! E' uscito il mio libro "Programmare con WPF 4.5.1". Clicca sulla copertina per informazioni!

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.
If you're not an Italian user, please visit my English blog

Le vostre visite

I'm a VB!

Guarda la mia intervista a Seattle

Follow me on Twitter!

Altri spazi

GitHub
I miei progetti open-source su GitHub

Article Categories

Archives

Post Categories

Image Galleries

Privacy Policy

WPF: esempio 'master-details' con il controllo DataGrid

Il WPF Toolkit, libreria di controlli open source a complemento di quelli standard offerti da WPF, mette a disposizione un controllo DataGrid destinato a WPF in .NET Framework 3.5 SP 1 (in attesa di .NET 4.0, in cui il controllo farà parte della libreria base con feature aggiuntive). Facemmo un’introduzione alla DataGrid in questo post.

 

Ci proponiamo ora di costruire un piccolo esempio di tipo master-details, sfruttando ADO.NET Entity Framework come modello a oggetti e la DataGrid per la presentazione e l’editing di dati tabulari. Nel nostro esempio, otterremo l’elenco dei clienti della nostra ipotetica azienda Northwind Traders e consentiremo la visualizzazione in dettaglio degli ordini richiesti da ciascun cliente. La nostra demo sarà costituita da due parti: la prima, la presente, in cui creeremo l’esempio ed accetteremo il layout standard offerto dalla DataGrid. Nella seconda vedremo come personalizzare il template delle celle della griglia con controlli personalizzati, al fine di renderne l’aspetto più user friendly.

 

Per il nostro esempio possiamo utilizzare Visual Basic 2008 Express Edition. Dopo aver creato un nuovo progetto WPF, aggiungiamo un Entity Data Model derivato dal database Northwind, in cui confluiranno le rappresentazioni delle tabelle Customers e Orders del predetto database. Se avete bisogno di una mano, potete seguire la procedura descritta in questo mio articolo su VB T&T.

 

Detto questo, ecco come si presenterà la nostra finestra principale al termine delle operazioni di design:

 

 

 

Passiamo quindi a scrivere il codice XAML per definire l’interfaccia. Innanzitutto, suddividiamo la griglia di default in questo modo, ossia in tre righe:

 

    <Grid>

        <Grid.RowDefinitions>

            <RowDefinition Height="30"/>

            <RowDefinition/>

            <RowDefinition Height="50"/>

        </Grid.RowDefinitions>

 

Nella prima riga è posizionata una ComboBox, dalla quale potremo selezionare il cliente di nostro interesse. Ecco il codice:

 

            <ComboBox ItemsSource="{Binding}" Name="CustomersCombo" Grid.Row="0"

                  IsSynchronizedWithCurrentItem="True" DisplayMemberPath="CompanyName"/>

 

Oltre al fatto che la combo verrà popolata per mezzo del data-binding (ItemsSource), notate la proprietà DisplayMemberPath che consente di specificare quale proprietà della sorgente dati assegnata in binding dovrà popolare il controllo.

 

Fatto questo, dalla toolbox di Visual Basic 2008 Express trasciniamo il controllo DataGrid, disponibile nella scheda WPF Toolkit. Questa operazione aggiungerà un riferimento all’assembly WPFToolkit.dll, presente nella GAC, e una dichiarazione di namespace Xml all’interno dell’elemento Window che permetterà di utilizzare i controlli esposti dal toolkit:

 

    xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"

 

Nel caso in cui otteniate un messaggio di errore in fase di drag’n’drop, potete eseguire queste due operazioni manualmente. Fatto questo, noterete l’aggiunta di un oggetto DataGrid allo XAML. Utilizzando la finestra delle proprietà, o scrivendo manualmente codice, modifichiamo l’oggetto in questo modo:

 

        <my:DataGrid Name="OrdersDataGrid" Grid.Row="1" IsSynchronizedWithCurrentItem="True"

                     AutoGenerateColumns="True" AlternatingRowBackground="Azure"

                     ItemsSource="{Binding}" CanUserAddRows="True" CanUserDeleteRows="True"

                     CanUserSortColumns="True" CanUserReorderColumns="True"

                     CanUserResizeColumns="True" CanUserResizeRows="True"/>

 

Alcune note: innanzitutto la generazione automatica delle colonne (AutoGenerateColumns), quindi il colore per righe alternate (AlternatingRowBackground), infine una serie di proprietà che consentano all’utente di modificare aspetto della griglia e dati contenuti. Già possiamo osservare che non abbiamo necessità, come invece per la ListView, di specificare manualmente le colonne poiché la DataGrid le genera per noi. Come vedremo nel post successivo, sebbene questo sia un layout standard può essere modificato in modo decisamente migliore.

 

Da ultimo, aggiungiamo i controlli per agire sui dati:

 

        <StackPanel Grid.Row="2" Orientation="Horizontal"  >

            <Button Width="100" Height="30" Margin="5" Content="Add order" Name="AddButton"/>

            <Button Width="100" Height="30" Margin="5" Content="Delete order" Name="DeleteButton"/>

            <Button Width="100" Height="30" Margin="5" Content="Save changes" Name="SaveButton"/>

        </StackPanel>

    </Grid>

 

Se non si sono verificati errori, l’aspetto della finestra sarà uguale alla figura illustrata all’inizio del post. Passiamo ora al file di code-behind, per scrivere un po’ di codice Visual Basic. A livello di classe, dichiariamo per prima cosa i due seguenti oggetti:

 

    Private NorthwindContext As New NORTHWNDEntities

    Private OrdersList As ObservableCollection(Of Orders)

 

La prima dichiarazione ottiene l’istanza del contesto. La seconda invece, dichiara una ObservableCollection quindi un tipo di collezione che supporta il data-binding di tipo two-ways e decisamente indicata nelle applicazioni WPF. Utilizziamo questa collezione per fare poi il binding dei dati all’interfaccia, in modo da lavorare sulla collezione stessa. Agendo su di essa, l’interfaccia collegata si aggiornerà automaticamente.

 

Scriviamo poi due metodi, uno che ottiene l’elenco dei clienti e uno che ottiene l’elenco degli ordini per il cliente specificato (vedi commenti):

 

    Private Function GetCustomers() As IQueryable(Of Customers)

        'Restituisce i clienti

        Return Me.NorthwindContext.Customers

    End Function

 

    Private Function GetOrders(ByVal CustomerID As String) As ObservableCollection(Of Orders)

 

        'Eseguo l'eager-loading utilizzando il metodo Include. E' necessario

        'perchè successivamente dovremo settare una relazione

        Return New ObservableCollection(Of Orders) _

                (From ord In Me.NorthwindContext.Orders.Include("Customers") _

                Where ord.Customers.CustomerID = CustomerID _

                Select ord)

 

    End Function

 

Il secondo metodo, in particolare, restituisce una ObservableCollection; questo perché tale oggetto potrà ricevere modifiche ai dati che contiene. Il passaggio successivo è quello di popolare la ComboBox con l’elenco dei clienti:

 

    Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

        Me.CustomersCombo.ItemsSource = Me.GetCustomers

    End Sub

 

Forse ora è più chiaro il perché dell’utilizzo della proprietà DisplayMemberPath nello XAML della Combo: stiamo infatti assegnando al controllo, come origine dati, una collezione. La citata proprietà ci permette di selezionare quale proprietà della collezione deve essere visualizzata.

Dobbiamo poi gestire l’evento SelectionChanged della Combo, che si verifica quando l’utente seleziona il cliente del quale vuole visualizzare gli ordini:

 

    Private Sub CustomersCombo_SelectionChanged(ByVal sender As System.Object, _

 ByVal e As System.Windows.Controls.SelectionChangedEventArgs) _

 Handles CustomersCombo.SelectionChanged

 

        'Ottengo l'istanza del cliente selezionato nella Combo

        Dim currentCustomer As Customers = CType(Me.CustomersCombo.SelectedItem, Customers)

 

        'Passo il suo ID al metodo GetOrders e popolo la collezione col risultato

        Me.OrdersList = Me.GetOrders(currentCustomer.CustomerID)

        'Assegno la sorgente dati alla DataGrid

        Me.OrdersDataGrid.ItemsSource = Me.OrdersList

 

    End Sub

 

L’ObservableCollection(Of Orders)ottenuta tramite il metodo GetOrders e che popola l’oggetto OrdersList diventa la sorgente dati per la DataGrid e l’assegnazione della proprietà ItemsSource finalizza il data-binding. Passiamo poi a scrivere i gestori di evento dei pulsanti. In primo luogo, quello di salvataggio:

 

    Private Sub SaveButton_Click(ByVal sender As System.Object, _

                                 ByVal e As System.Windows.RoutedEventArgs) _

                                 Handles SaveButton.Click

 

        Try

            Me.NorthwindContext.SaveChanges()

        Catch ex As Exception

            MessageBox.Show(ex.ToString)

        End Try

    End Sub

 

Come probabilmente già sapete, è sufficiente richiamare il metodo SaveChanges del contesto e null’altro, poiché il contesto stesso è in grado di tenere traccia delle modifiche fatte nei confronti delle entità. Il codice seguente gestisce l’aggiunta di un nuovo ordine all’elenco:

 

    Private Sub AddButton_Click(ByVal sender As System.Object, _

                                ByVal e As System.Windows.RoutedEventArgs) _

                                Handles AddButton.Click

        Dim ord As New Orders

        ord.Customers = CType(Me.CustomersCombo.SelectedItem, Customers)

 

        Me.OrdersList.Add(ord)

 

        Me.NorthwindContext.AddToOrders(ord)

    End Sub

 

L’istanza del nuovo ordine riceve l’assegnazione della proprietà Customers, ossia del cliente cui deve essere relazionato. Quest’ultimo è determinato ottenendo il cliente attualmente selezionato nella ComboBox. Il nuovo ordine viene aggiunto alla collezione collegata all’interfaccia e al contesto.

Da ultimo, il codice per la rimozione di un ordine dalla DataGrid:

 

    Private Sub DeleteButton_Click(ByVal sender As System.Object, _

                                   ByVal e As System.Windows.RoutedEventArgs) _

                                   Handles DeleteButton.Click

 

        Try

 

            Dim currentProduct As Orders = CType(Me.OrdersDataGrid.SelectedItem, Orders)

 

            Me.OrdersList.Remove(currentProduct)

            Me.NorthwindContext.DeleteObject(currentProduct)

 

        Catch ex As Exception

 

        End Try

    End Sub

 

Il codice ottiene l’istanza dell’ordine selezionato nella griglia, per poi rimuoverlo dai dati a disposizione. Possiamo finalmente avviare l’applicazione per ottenere il seguente risultato:

 

 

 

Possiamo così modificare i dati esistenti, aggiungerne di nuovi o rimuoverli, il tutto intervenendo direttamente sulle celle della griglia. Se volete accertarvi del fatto che nuovi dati vengano correttamente persistiti nel database, vi basterà cliccare Save Changes: se tutto va a buon fine, il valore della proprietà OrderID passa da 0 a quello autovalorizzato dal database stesso.

 

Come detto, questo è il layout standard della DataGrid, inoltre vengono generate anche colonne che effettivamente non ci interessano. Nel prossimo post vedremo come personalizzare il layout della DataGrid customizzando il DataTemplate delle celle e generando manualmente le colonne.

 

Il progetto a corredo del presente post è scaricabile da questo indirizzo dell’area download di Visual Basic Tips & Tricks.

 

Alessandro

Print | posted on venerdì 3 aprile 2009 03:18 | Filed Under [ Visual Basic Windows Presentation Foundation ]

Powered by:
Powered By Subtext Powered By ASP.NET