WPF, LINQ e DataBinding

WPF, LINQ e Binding
Con questo articolo voglio giocare con un paio di nuone tecnologie offerte da Microsoft.
Seguendo l’esempio offerto da Beatriz Costa al TechEd 2008, ho sviluppato qualcosa di analogo.
Librerie e Libri
L’esempio in se non è nulla di complicato ma è bello poter vedere in azione queste nuove tecnologie.
Il progetto che andremo a realizzare con VS2008 sarà un WPF Browser Application.
La nostra pagina principale sarà Page1.xaml e aggiungeremo solamente 3 files in più al progetto:
 
XMLFile1.xml
Questo sarà il nostro file d’appoggio, il quale conterrà le informazioni che vogliamo presentare all’utente.
Parte del contenuto di questo file si presenta così:
<ListBooks>
<BookObjectTitle="Extreme Programming Explained: Embrace Change">
<
ImageFileName>Images\xp_guide_small.jpg</ImageFileName>
<
Author>Kent Beck</Author>
<
Published>25 Nov 2004</Published>
</BookObject>
Notate, avrete bisogno di una directory Images dove dovrete andare a inserire l’immagine da caricare relativa al libro.
BookObject
Questa è una semplicissima classe contenitore che useremo per definire un libro all’interno della nostra libreria.
    public class BookObject
    {
        public string Title { get; set; }
        public string ImageFileName { get; set; }
        public string Author { get; set; }
        public string Published { get; set; }
 
        public override string ToString()
        {
            return Title + " " + Author;
        }
    }
 
Library
Finalmente un pò di codice.
    public class Library
    {
        public Library()
        {
            Uri res = new Uri(@"pack://application:,,,/XMLFile1.xml", UriKind.Absolute);
 
            // The Application object wraps a set of XAML files and creates a shared data environment between the
            // pages. The Application object loads with the initial load and provides shared variables at that time.
            StreamResourceInfo sri = App.GetResourceStream(res);
            StreamReader reader = new StreamReader(sri.Stream);
            XDocument booksXml = XDocument.Load(reader);
 
            _libraryObjects = new List<BookObject>();
 
            var book = from books in booksXml.Descendants("BookObject")
                       select new BookObject
                       {
                           Title = books.Attribute("Title").Value,
                           ImageFileName = books.Element("ImageFileName").Value,
                           Author = books.Element("Author").Value,
                           Published = books.Element("Published").Value
                       };
 
            foreach (var bd in book)
                _libraryObjects.Add(bd);
        }
 
        private List<BookObject> _libraryObjects;
        public List<BookObject> LibraryObjects
        {
           get { return _libraryObjects; }
        }
    }
 
Analizziamo nel dettaglio il lavoro di questa classe.
Per prima cosa dovrà aprire il nostro file XMLFile1.xml e leggerne il contenuto.

Per motivi di sicurezza i progetti di questo tipo, Browser Application, non hanno diritti di lettura e scrittura sul nostro file system se non nelle directory utilizzate da IsolatedStorageFile.
Per questo motivo dovremo specificare nelle proprietà del XMLFile1.xml:
·         Build Action: Resource
In questa maniera il file verrà inserito all’interno del nostro eseguibile e sarà disponibile per la lettura.

Per poter leggere il file, WPF, mette a disposizione le
URI (uniform resource identifiers).
Quindi specificheremo un nuovo URI, puntando sul file all’interno della nostra applicazione.
Avendo adesso il riferimento al nostro file, dobbiamo farlo leggere a LINQ che non è a conoscenza di come sono organizzate le nostre risorse.
Quindi andremo a prendere la risorsa tramite la classe Application.
La classe Application è un’interfaccia tra il nostro sistema e l’applicazione. È l’entry point delle nostre applicazioni WPF.
Nel nostro caso specifico, troveremo questa nel file App.xaml.cs
Per ulteriori informazioni
quì.
Acquisito il riferimento al nostro file e creati gli Streams opportuni, lasceremo a LINQ l’arduo compito di leggere i dati all’interno del file.
Questo procedimento è alquanto semplice, almeno nel nostro caso.
Creando una query come quella all’interno del nostro codice, LINQ si occuperà di tirar fuori tutti i dati relativi ai libri presenti nel file XML e inserirà questi dati all’interno della variabile book.
Adesso che abbiamo a disposizione tutti i dati che sono all’interno del nostro file xml, ne inseriremo i riferimenti all’interno della nostra collection:
List<BookObject> _libraryObjects;
 
Page1.xaml
A questo punto la nostra applicazione è pronta all’80%.
Ci rimane solamente da bindare i dati all’interno della nostra pagine XAML e definire come vogliamo visualizzarli.
Per quanto concerne il concetto di bindare i dati all’interno di un’applicazione WPF vi consiglio di vedere il video di Beatriz Costa, il quale vi potrà chiarire le idee.
Sappiate solamente che il binding è una relazione che creiamo tra la nostra UI e la nostra sorgente di dati.

Quello che vedremo in questo tutorial è come bindare dei dati presenti in memoria che vengono modificati durante l’esistenza dell’applicazione.
    <StackPanel x:Name="LayoutRoot" HorizontalAlignment="Center" VerticalAlignment="Top">
        <ListBox ItemsSource="{Binding Source={StaticResource myLibrary}, Path=LibraryObjects}"
            ScrollViewer.VerticalScrollBarVisibility="Auto" Height="480" Width="500" />
        <!--<ComboBox ItemsSource="{Binding Source={StaticResource myLibrary}, Path=LibraryObjects}" SelectedIndex="0"/>-->
    </StackPanel>
Con queste poche righe di XAML noi stiamo già bindando i nostri dati e potrebbero essere già disponibili.
Se non ci credere, provate a completare in questa maniera:
·         Inserite il seguente codice sopra lo StackPanel poc’anzi definito:
    <Page.Resources>
        <local:Library x:Key="myLibrary" />
Ecco adesso la vostra ListBox con i dati bindati.
Già così abbiamo ottenuto ciò che volevamo ma, per concludere, diamo un’aspetto migliore ai nostri dati.
Per far ciò dobbiamo solamente dire a WPF come vogliamo, appunto, visualizzarli.
Per farlo bisogna utilizzare un
DataTemplate.
Il nostro DataTemplate è stato definito nella seguente maniera:
        <DataTemplate DataType="{x:Type local:BookObject}">
            <StackPanel Orientation="Horizontal" Margin="3" TextBlock.FontSize="12" TextBlock.FontFamily="Tahoma">
                <Image Source="{Binding Path=ImageFileName}" Margin="0,0,3,0" />
                <StackPanel Width="500">
                    <TextBlock FontWeight="Bold" Text="{Binding Title}" />
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Author}" />
                        <TextBlock Text="{Binding Published}" />
                    </StackPanel>
                </StackPanel>
            </StackPanel>
        </DataTemplate>
    </Page.Resources>
In pratica stiamo definendo i StackPanel che conterranno i nostri dati, cosa dovranno contenere e come visualizzarli.
Esempio, il primo StackPanel definisce come il testo verrà visualizzato e al suo interno ha un Controllo di tipo Image che viene bindato all’oggetto ImageFileName presente all’interno della classe BookObject.
 
Nel codice ho lasciato commentato un Control di tipo ComboBox.
Provate a decommentare la ComboBox e a commentare la ListBox, e potrete capire come le WPF vi aiuteranno a relazionarvi e come sono strettamente relazionate a pattern quali MVP.
Il progetto completo lo trovate quì.
 
Tags: