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

Leggi il Capitolo 9 di esempio

9. LINQ in Windows Presentation Foundation

In questo capitolo vedremo come realizzare applicazioni per l’accesso ai dati congiuntamente ad interfacce grafiche avanzate con WPF.

Nota – gli argomenti trattati in questo capitolo si applicano anche a Visual Basic 2008 Express Edition

Utilizzo di LINQ in applicazioni WPF

Windows Presentation Foundation è la branca di .NET Framework 3.x dedicata alla realizzazione di interfacce grafiche avanzate, dagli elevati contenuti multimediali. Tale tecnologia si basa sulle librerie Microsoft® DirectX® e permette di ottenere esperienze utente davvero sorprendenti, con uno sforzo relativamente contenuto. In questa sede non sarà possibile entrare nel dettaglio di WPF, poiché trattiamo LINQ, ma osserveremo come quest’ultima tecnologia sia utilizzabile nelle applicazioni WPF, consentendo allo sviluppatore di presentare i dati all’utente finale attraverso interfacce decisamente accattivanti, per la cui produzione Microsoft ha realizzato uno specifico linguaggio di markup, di derivazione Xml, chiamato XAML (eXtensible Application Markup Language) che si occupa di gestire la fase di design e che può essere utilizzato sia da sviluppatori che da grafici professionisti. Per ovvie ragioni, non è possibile entrare nello specifico di XAML, ma è opportuno ricordare che, in questo particolare linguaggio, i controlli dell’interfaccia hanno struttura di elementi Xml, mentre le proprietà dei controlli hanno le caratteristiche degli attributi Xml.

 

Nota – per informazioni di dettaglio su Windows Presentation Foundation e il linguaggio XAML, potete consultare il libro “Programmare con .NET Framework 3.x” di Alessandro Del Sole.

 

Per raggiungere gli obiettivi proposti nel capitolo non è indispensabile conoscere approfonditamente WPF; tuttavia, in considerazione del codice che illustreremo, particolarmente articolato, è preferibile che il lettore abbia un’infarinatura sul linguaggio XAML e sul funzionamento di data-binding, stili e control template in questa particolare tecnologia. Ad ogni buon conto, durante l’esposizione ci soffermeremo sulle singole tematiche cercando di renderle comprensibili anche allo sviluppatore meno esperto di WPF. C’è da premettere che in Windows Presentation Foundation è possibile utilizzare tutti i provider LINQ che abbiamo visto finora. Questo offre grandi possibilità allo sviluppatore. Noi ci soffermeremo su due particolari provider, LINQ-to-SQL per la visualizzazione di dati memorizzati in un database, attraverso un’interfaccia grafica avanzata, e LINQ-to-Xml per la creazione a run-time di controlli WPF. Iniziamo subito col parlare di LINQ-to-SQL, rimandando al Capitolo 4 per le nozioni introduttive su questa infrastruttura.

LINQ-to-SQL e WPF: dati e interfacce avanzate

Sorgente di esempio: Capitolo 9\LinqSqlWpf

 

In questa sezione ci occuperemo di creare un’applicazione basata su Windows Presentation Foundation in grado di leggere dal database Northwind alcuni dati, come, per esempio, il nome, il cognome e la data di assunzione di ciascun impiegato, corredati dalle rispettive fotografie e di mostrarle all’utente attraverso un’interfaccia grafica di migliore qualità.

Creazione del progetto e mapping dei dati

In primo luogo, avviate Visual Studio 2008 e, dal menu File, selezionate il comando Nuovo|Progetto. Quando la finestra Nuovo progetto compare, selezionate il modello Applicazione WPF e assegnate al progetto il nome LinqSqlWpf (vedi Figura 9.1).

 

 

Figura 9.1 – La scelta del modello per la creazione di un’applicazione WPF.

 

Quando la creazione del nuovo progetto è completata, potrete osservare come il designer di Visual Studio 2008 sia suddivisa in due aree, quella superiore relativa al designer e quella inferiore relativa all’editor di codice XAML (vedi Figura 9.2).

 

 

Figura 9.2 – Il designer di Visual Studio 2008 relativo al progetto WPF.

 

La prima operazione da eseguire, prima di scrivere codice XAML e Visual Basic, è quella di definire l’origine dati. Riutilizzando le modalità descritte nel Capitolo 4, al quale si rimanda per i chiarimenti del caso, eseguite, in primo luogo, la connessione al database Northwind attraverso la finestra Esplora server (Esplora database in Visual Basic Express). Quando la connessione è stabilita, è necessario aggiungere al progetto una classe LINQ-to-SQL. Dal menu Progetto, selezionate il comando Aggiungi nuovo elemento e, quando compare l’omonima finestra, selezionate il modello di elemento chiamato Classi LINQ-to-SQL assegnando al file il nome Northwind.dbml (vedi Figura 9.3).

 

 

Figura 9.3 – L’aggiunta di una classe LINQ-to-SQL al progetto.

 

Quando la classe è aggiunta al progetto e il designer OR/M è attivo, trascinate, come sapete fare, la tabella Employees del database Northwind dalla finestra Esplora server sul designer OR/M, affinché venga avviato il procedimento di mapping della tabella, sotto forma di classe .NET/entità. Quando il designer è pronto e l’entità Employees viene mostrata, facciamo una piccola modifica. Come accennato all’inizio della sezione, vogliamo che successivamente, tramite interfaccia, sia possibile visualizzare, oltre ai dati principali di ciascun impiegato, anche la relativa foto. Affinché questo sia possibile, è necessario modificare il tipo di dato della proprietà Photo, da System.Data.Linq.Binary a System.Byte(), cioè un array di byte. Ciò posto, selezionate la proprietà Photo nell’entità e modificatene il valore della proprietà Type in Byte(), utilizzando la Finestra delle proprietà (vedi Figura 9.4).

 

 

Figura 9.4 – La modifica della proprietà Photo dell’entità, come array di Byte.

 

Questo farà si che Visual Studio modifichi il codice sottostante all’entità, facendo riferimento al nuovo tipo di dato. Al contrario delle applicazioni Windows Forms, non avendo la possibilità di sfruttare alcun automatismo, non sarà necessario aggiungere alcuna origine dati. Ci occorrerà solamente fare riferimento al DataContext, che vedremo in azione nel prossimo paragrafo, associandolo all’interfaccia grafica. Prima, però, predisporremo una classe che ci permetta di convertire le immagini recuperate dal database in un formato utilizzabile da WPF. Nella finestra Esplora soluzioni, fate clic sul file Window1.xaml, quindi clic sul pulsante Visualizza codice, che attiverà l’editor di codice Visual Basic. Se avete già dimestichezza con WPF, sapete che a ciascun file di codice XAML è associato un file di codice gestito, noto come file di code-behind. Definiremo una classe chiamata ImageDataConverter che, attraverso l’implementazione dell’interfaccia IValueConverter, restituirà l’immagine sotto forma di oggetto utilizzabile da WPF. Il codice è il seguente:

 

Public Class ImageDataConverter

    Implements IValueConverter

 

    Public Function Convert(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert

        Return value

    End Function

 

    Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack

        Throw New NotSupportedException

    End Function

End Class

 

Compilate il progetto, affinché tutti le modifiche fatte risultino aggiornate. Ora, sempre nella finestra Esplora soluzioni, fate clic sul pulsante Visualizza finestra di progettazione, al fine di tornare all’editor di codice XAML e al designer. A questo punto siamo pronti per progettare l’interfaccia grafica della nostra applicazione, sfruttando la dinamicità del codice XAML.

Per i meno esperti: risorse su WPF

Il prossimo paragrafo sarà cruciale nella realizzazione della nostra applicazione, poiché darà sfogo allo scopo principale di Windows Presentation Foundation: la realizzazione di un’interfaccia grafica avanzata. Sebbene lo ricorderemo più avanti, possiamo anticipare che in questa sede non è possibile trattare nel dettaglio WPF e XAML, per motivi di spazio e per non andare fuori argomento. Si segnalano, pertanto, le seguenti risorse su WPF per il lettore che abbia desiderio di approfondire gli argomenti:

 

·         Libro “Programmare con .NET Framework 3.x” di Alessandro Del Sole, edito da Edizioni FAG Milano – ISBN 9788882336868:

http://www.fag.it/scheda.aspx?ID=21753

·         Documento Microsoft Belgium & Benelux: Styles and Triggers in WPF:

http://www.microsoft.com/belux/msdn/nl/community/columns/gillcleeren/wpf_stylesandtriggers.mspx

·         Articolo Introduzione a Windows Presentation Foundation, di Alessandro Del Sole:

http://www.visual-basic.it/articoli/adsIntroWPF.htm

·         Articolo Gli stili in Windows Presentation Foundation, di Alessandro Del Sole:

http://www.visual-basic.it/articoli/adsStiliWPF.htm

 

Dopo avervi fornito alcune risorse di sicuro interesse, siamo pronti per passare alla costruzione della nostra interfaccia grafica.

Costruzione dell’interfaccia e data-binding

Nell’ambito dell’interfaccia grafica, lavoreremo con codice XAML piuttosto che col designer. Sicuramente strumenti come Microsoft Expression Blend si fanno preferire alle limitazioni di Visual Studio 2008 (che è pur sempre uno strumento per sviluppatori e non per disegnatori) ma XAML ci permette di ottenere gli stessi risultati. In primo luogo, aggiungiamo alcune cose alla dichiarazione dell’oggetto Window, per ampliarne la larghezza e dichiarare un identificatore che rappresenti il namespace di primo livello, permettendoci di referenziarlo da XAML stesso:

 

XAML

 

<Window x:Class="Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

xmlns:local="clr-namespace:LinqSqlWpf"

Title="Window1" Height="300" Width="550">

 

Nell’interfaccia visualizzeremo i record del database all’interno di un controllo ListView, che ben si presta al nostro scopo di mostrare testo e immagini. In considerazione di questo, definiamo, in primo luogo, alcune risorse a livello di finestra: un identificatore che ci permetterà di richiamare da XAML la classe ImageDataConverter, precedentemente implementata, quindi uno stile e un modello di controllo per ciascun elemento della ListView, in particolar modo per quando esso viene selezionato:

 

    <Window.Resources>

        <local:ImageDataConverter x:Key="imageConverter" />

 

        <Style x:Key="EmployeeListViewItemStyle" TargetType="{x:Type ListViewItem}">

             <Style.Triggers>

             </Style.Triggers>

             <Setter Property="Template" Value="{DynamicResource EmployeeListBoxItemControlTemplate}"/>

        </Style>

 

        <ControlTemplate x:Key="EmployeeListBoxItemControlTemplate" TargetType="{x:Type ListBoxItem}">

             <Border x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">

                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>

             </Border>

             <ControlTemplate.Triggers>

                    <Trigger Property="IsSelected" Value="True">

                           <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>

                           <Setter Property="Background" TargetName="Bd">

                                  <Setter.Value>

                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                                               <GradientStop Color="#FF000000" Offset="0"/>

                                               <GradientStop Color="#FFFFFFFF" Offset="1"/>

                                        </LinearGradientBrush>

                                  </Setter.Value>

                           </Setter>

                    </Trigger>

                    <MultiTrigger>

                           <MultiTrigger.Conditions>

                                  <Condition Property="IsSelected" Value="True"/>

                                  <Condition Property="Selector.IsSelectionActive" Value="False"/>

                           </MultiTrigger.Conditions>

                           <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>

                           <Setter Property="Background" TargetName="Bd">

                                  <Setter.Value>

                                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                                               <GradientStop Color="#FF000000" Offset="0"/>

                                               <GradientStop Color="#FFFFFFFF" Offset="1"/>

                                        </LinearGradientBrush>

                                  </Setter.Value>

                           </Setter>

                    </MultiTrigger>

                    <Trigger Property="IsEnabled" Value="False">

                           <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>

                    </Trigger>

             </ControlTemplate.Triggers>

        </ControlTemplate>

    </Window.Resources>

 

L’elemento ControlTemplate definisce il modello a cui deve conformarsi l’elemento della ListView, in particolar modo alla sua selezione, mostrando uno sfondo a gradiente. La selezione dell’elemento è determinata dal MultiTrigger sulla proprietà IsSelected. Il modello così definito viene referenziato dall’elemento Style che lo assegna al particolare controllo per cui esso è progettato. Come potete facilmente intuire, lo XAML sopra esposto diventa di più semplice comprensione se avete almeno conoscenze di base di Windows Presentation Foundation, in particolare se sapete cosa sono e come si usano gli stili e i control template. Diversamente, ci rendiamo conto della difficoltà di comprensione che lo sviluppatore che non ha mai avuto a che fare con WPF può incontrare ma, per motivi di spazio, e per non andare fuori argomento, siamo costretti a restringere la discussione intorno allo XAML per concentrarci su LINQ. Il codice seguente dichiara i controlli veri e propri, che verranno utilizzati nell’interfaccia. La finestra sarà così strutturata: un contenitore Grid verrà suddiviso in due aree, una superiore, in cui insisterà un controllo Border e una inferiore in cui insisterà la ListView, che suddivideremo in ulteriori aree ma che descriveremo dopo. Ora definiamo la prima griglia e il controllo Border che essa contiene:

 

    <Grid>

 

        <Grid.RowDefinitions>

            <RowDefinition Height="80"/>

            <RowDefinition/>

        </Grid.RowDefinitions>

 

        <Border Grid.Row="0" Height="Auto" VerticalAlignment="Top" BorderBrush="#FFC81717">

             <Border.Background>

                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                           <GradientStop Color="#FF000000" Offset="0"/>

                           <GradientStop Color="#FF0A0A0A" Offset="1"/>

                           <GradientStop Color="#FFBDBDD0" Offset="0.527"/>

                    </LinearGradientBrush>

             </Border.Background>

           

        </Border>

 

Gli elementi RowDefinition della Grid suddividono in due righe (di cui la prima alta 80 pixel). Il controllo Border viene posizionato nella prima riga (Grid.Row=”0”) e ne viene impostato lo sfondo a gradiente. Definiamo ora la ListView, che risiederà nella seconda riga, di cui daremo alcune annotazioni successivamente:

 

            <ListView  Name="listView1" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" Margin="0,-0.984,0,0" Grid.Row="1" ItemContainerStyle="{DynamicResource EmployeeListViewItemStyle}">

            <ListView.ItemTemplate>

                <DataTemplate>

                    <Border Margin="5" BorderThickness="1" BorderBrush="SlateGray" CornerRadius="4">

                        <Grid Margin="3">

                            <Grid.RowDefinitions>

                                <RowDefinition></RowDefinition>

                                <RowDefinition></RowDefinition>

                                <RowDefinition></RowDefinition>

                                <RowDefinition></RowDefinition>

                            </Grid.RowDefinitions>

                            <Grid.ColumnDefinitions>

                                <ColumnDefinition/>

                                <ColumnDefinition/>

                            </Grid.ColumnDefinitions>

                                               <StackPanel Grid.Column="0">

                                  <TextBlock FontWeight="Bold" Text="{Binding Path=LastName}"></TextBlock>

                                  <TextBlock Grid.Row="1" Text="{Binding Path=FirstName}"></TextBlock>

                                  <TextBlock Grid.Row="2" Text="{Binding Path=HireDate}"></TextBlock>

                                               </StackPanel>

                            <Image Grid.Column="1"

                                   Width="50" Height="100"

                                   Source="{Binding Path=Photo , Converter={StaticResource imageConverter}}"/>

                        </Grid>

                    </Border>

                </DataTemplate>

            </ListView.ItemTemplate>

        </ListView>

 

Di particolare rilevanza, in questo frangente, è l’elemento ListView.ItemTemplate, che predispone la “forma” di ciascun elemento. In particolare, attraverso l’elemento DataTemplate, si definisce il modello di visualizzazione dei dati per ciascun ListViewItem. Qui viene stabilito che ciascun elemento della ListView sarà costituito da un bordo, con spigoli smussati, al cui interno insiste una griglia suddivisa in due colonne. Nella prima colonna ci sarà un contenitore StackPanel che, per ciascuna riga della griglia, mostrerà, tramite un controllo TextBlock, alcune proprietà dell’impiegato, come il nome, il cognome e la data di assunzione. Notate come la proprietà Text di ciascun TextBlock sia associata tramite binding a una proprietà specifica della classe Employees (Binding Path). La seconda colonna, invece, conterrà la fotografia dell’impiegato. Anche in questo caso si sfrutta il data-binding ma, tramite l’attributo Converter, si specifica la classe che eseguirà la conversione dal formato System.Byte a un formato utilizzabile in WPF, quindi la classe che abbiamo dichiarato in precedenza.

Giusto per abbellimento, aggiungiamo di seguito un ulteriore TextBlock che mostri un titolo rappresentativo, con sfondo e colore di primo piano a gradiente:

 

            <TextBlock Text="Northwind Traders Employees" TextWrapping="Wrap" FontWeight="Bold" FontStyle="Italic" FontSize="36" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">

            <TextBlock.Background>

                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                           <GradientStop Color="#FF000000" Offset="0"/>

                           <GradientStop Color="#FF0A0A0A" Offset="1"/>

                           <GradientStop Color="#FFBDBDD0" Offset="0.527"/>

                    </LinearGradientBrush>

            </TextBlock.Background>

            <TextBlock.Foreground>

                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">

                           <GradientStop Color="#FF0B6422" Offset="0"/>

                           <GradientStop Color="#FFFDFF00" Offset="0.406"/>

                           <GradientStop Color="#FF0B6422" Offset="0.661"/>

                    </LinearGradientBrush>

            </TextBlock.Foreground>

            </TextBlock>

    </Grid>

</Window>

 

La fase di design è così completata. Ovviamente, nel designer vedrete in modo evidente solo l’ultimo TextBlock e l’aggiunta della ListView, questo perché i dati saranno caricati dal database a run-time. Proprio a questo proposito è necessario scrivere codice Visual Basic che effettui il caricamento dei dati. Attivando nuovamente l’editor di codice Visual Basic sul file Window1.xaml, possiamo gestire l’evento Load dell’oggetto Window1 affinché, ottenendo l’istanza del DataContext e tramite una query LINQ, popoli la ListView:

 

Private northwindContext As New _

        NorthwindDataContext

 

Private Sub Window1_Loaded(ByVal sender As _

Object, ByVal e As _

System.Windows.RoutedEventArgs) Handles Me.Loaded

 

    Dim query = From employee In _

                northwindContext.Employees _

                Select New With { _

                        employee.LastName, _

                        employee.FirstName, _

                        employee.HireDate, _

                        employee.Photo}

 

    Me.listView1.ItemsSource = query

End Sub

 

La query LINQ estrae il cognome (LastName), il nome (FirstName), la data di assunzione (HireDate) e la fotografia di ciascun impiegato, assegnando il tutto a una collezione di tipi anonimi. Questa collezione, denominata query, viene poi assegnata alla proprietà ItemsSource della ListView e ne consente il popolamento. Se ora provate ad avviare l’applicazione, otterrete l’interessante risultato mostrato in Figura 9.5.

 

 

Figura 9.5 – L’applicazione di esempio mostra dati e foto degli impiegati.

 

Come potete osservare, l’interfaccia è sicuramente molto più accattivante di quella Windows Forms e, se avete dimestichezza con WPF, sapete molto bene che lo sforzo da fare per ottenere questo risultato non è poi così dispendioso, grazie alla potenza di XAML e dell’architettura dei controlli WPF, altamente personalizzabili. Potreste poi prevedere la possibilità di aggiungere caselle di testo per la ricezione e la modifica dei dati e il successivo invio al database, utilizzando le metodologie di Insert/Update/Delete viste nel Capitolo 4 e il metodo SubmitChanges del DataContext, che funziona in maniera identica anche in WPF. Riassumendo, abbiamo visto un esempio di utilizzo di LINQ-to-SQL in ambito WPF. Vedremo ora un altro provider LINQ in azione, LINQ-to-Xml, al fine di generare dinamicamente file di codice XAML e quindi controlli WPF.

LINQ-to-XML e XAML: interfacce WPF dinamiche

Come avete visto nella prima sezione di questo capitolo, o comunque se avete già avuto modo di conoscere Windows Presentation Foundation in altre sedi, il lato design di queste particolari applicazioni è gestito tramite il linguaggio di markup chiamato XAML (eXtensible Application Markup Language), realizzato da Microsoft e che ha tipica struttura gerarchica Xml. Per ovvie ragioni, non è possibile entrare nello specifico di XAML, ma è opportuno ricordare che, in questo particolare linguaggio, i controlli dell’interfaccia hanno struttura di elementi Xml, mentre le proprietà dei controlli hanno le caratteristiche degli attributi Xml.

Questo ci porta a considerare, in modo abbastanza evidente, che LINQ-to-Xml e i valori Xml letterali di Visual Basic 2008 possono essere utilizzati per creare file di codice XAML o, viceversa, di leggerli e interpretarli al fine di istanziare dinamicamente controlli utente WPF. Nel corso del paragrafo creeremo, quindi, un’applicazione dimostrativa che eseguirà proprio queste operazioni. I lettori ai quali è indirizzato questo paragrafo, quindi, sono coloro che già hanno almeno nozioni di base sull’organizzazione di un’applicazione WPF. Se non avete mai creato applicazioni WPF, questo paragrafo può comunque costituire uno spunto per iniziare. Dopo aver avviato Visual Studio 2008, dal menu File selezionate il comando Nuovo|Progetto. Quando compare la finestra Nuovo progetto, selezionate il modello chiamato Applicazione WPF (sempre con riferimento ai progetti Visual Basic), quindi assegnate al progetto il nome LinqXaml (vedi Figura 9.6), infine fate clic su OK.

 

 

Figura 9.6 – La finestra Nuovo progetto per la creazione di un’applicazione WPF.

 

Definiamo ora il compito che la nostra applicazione dovrà eseguire. Essa si occuperà di ottenere l’elenco dei processi attivi, salvare l’elenco sotto forma di un controllo WPF ListBox (memorizzandolo in un file .Xaml) e mostrare l’elenco stesso nella finestra principale, dopo aver caricato il codice XAML dal file creato dinamicamente. Con riferimento allo XAML proposto per impostazione predefinita da Visual Studio, l’unica modifica riguarda il contenitore Grid, al quale è necessario assegnare un identificatore che ci permetterà di utilizzare il controllo da codice Visual Basic:

 

XAML:

 

<Grid Name="Grid1" />

 

Subito dopo si passa alla scrittura di codice Visual Basic, pertanto attivate questo editor. .NET Framework mette a disposizione un importante namespace, chiamato System.Windows.Markup, che permette di eseguire la manipolazione di file di codice XAML all’interno di codice gestito, piuttosto che da designer. Quindi, poiché noi dovremo fare proprio questo, è necessario aggiungere la seguente direttiva Imports:

 

Imports System.Windows.Markup

 

Il file di codice XAML verrà creato sfruttando i valori Xml letterali di Visual Basic 2008. Ciascun file di codice XAML deve rifarsi a determinati schemi Microsoft, specifici per WPF, i quali definiscono alcuni namespace Xml. Tali namespace possono essere rilevati nel file di codice Window1.xaml, che è stato creato da Visual Studio all’atto della creazione del nuovo progetto. Ciò posto, anche tali namespace Xml devono essere importati, nel modo seguente:

 

Imports <xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">

 

Imports <xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

Si passa poi alla predisposizione di codice operativo. Vogliamo che l’elenco dei processi attivi sia determinato al caricamento della finestra principale, quindi all’interno dell’evento Loaded, che inizia nel modo seguente:

 

Private Sub Window1_Loaded(ByVal sender As _

            Object, ByVal e As _

            RoutedEventArgs) Handles Me.Loaded

 

   Dim processes = From proc In _

                   Process.GetProcesses _

                   Select proc.ProcessName

 

Questa semplicissima interrogazione, basata su LINQ-to-Objects, ottiene l’elenco dei processi attivi (metodo Process.GetProcesses) e seleziona il nome di ciascun processo (proprietà ProcessName).

Il passaggio successivo è quello di creare un file di codice XAML, che dichiari un controllo ListBox e tanti oggetti ListBoxItem quanti sono i processi attivi. Sfruttando i valori Xml letterali e le espressioni incorporate, di cui ormai siete esperti, il procedimento è davvero banale:

 

   Dim UI = <ListBox

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

 

               <%= From p In processes _

                   Order By p _

                   Select <ListBoxItem>

                             <%= p %>

                          </ListBoxItem> %>

             </ListBox>

            

            

Come potete osservare, in questo modo siamo in grado di creare, da codice Visual Basic, un file XAML perfettamente funzionante e aderente agli schemi richiesti. L’espressione incorporata aggiunge un nuovo oggetto ListBoxItem, il cui valore è costituito dal nome di un processo, per ciascun processo esistente nell’elenco. La riga di codice successiva salva il codice XAML in un nuovo file:

 

         

  UI.Save(AppDomain.CurrentDomain.BaseDirectory _

           + "DynamicUI.xaml")

 

La riga successiva, invece, ottiene legge il contenuto del file di codice XAML e lo converte nel corrispondente controllo WPF. Il caricamento e l’interpretazione del contenuto del file di codice sono a cura del metodo Load della classe XamlReader:

 

   Dim listBoxDinamica As ListBox = _

       CType(XamlReader.Load(UI.CreateReader), _

       ListBox)

 

Poiché tale metodo riceve come argomento un oggetto XmlReader, viene utilizzato il metodo CreateReader della classe XElement (l’istanza è l’oggetto UI) che restituisce proprio un oggetto del tipo richiesto. Una volta caricato e istanziato il controllo, lo si aggiunge al contenitore Grid1, attraverso il seguente codice:

 

  Grid1.Children.Add(listBoxDinamica)

End Sub

 

Fatto questo, sarà sufficiente avviare l’applicazione premendo F5, per vedere, dopo qualche secondo, una nuova ListBox che contiene l’elenco di tutti i processi attivi (vedi Figura 9.7).

 

 

Figura 9.7 – L’applicazione di esempio mostra l’elenco dei processi attivi, generato dinamicamente con LINQ.

 

Il risultato è stato quindi ottenuto creando dinamicamente un elemento dell’interfaccia grafica WPF, sfruttando i valori Xml letterali di Visual Basic 2008. Il file di codice generato, quindi, diventa simile al seguente (l’elenco dei processi varia, ovviamente, da computer a computer):

 

<?xml version="1.0" encoding="utf-8"?>

<ListBox xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">

  <ListBoxItem>ACEngSvr</ListBoxItem>

  <ListBoxItem>ACMON</ListBoxItem>

  <ListBoxItem>ALU</ListBoxItem>

  <ListBoxItem>conime</ListBoxItem>

  <ListBoxItem>csrss</ListBoxItem>

  <ListBoxItem>csrss</ListBoxItem>

  <ListBoxItem>DMedia</ListBoxItem>

  <ListBoxItem>dwm</ListBoxItem>

  <ListBoxItem>explorer</ListBoxItem>

  <ListBoxItem>HControl</ListBoxItem>

  <ListBoxItem>Idle</ListBoxItem>

  <ListBoxItem>inetinfo</ListBoxItem>

  <ListBoxItem>KBFiltr</ListBoxItem>

  <ListBoxItem>LinqXAML.vshost</ListBoxItem>

  <ListBoxItem>lsass</ListBoxItem>

  <ListBoxItem>lsm</ListBoxItem>

  <ListBoxItem>mqsvc</ListBoxItem>

  <ListBoxItem>mqtgsvc</ListBoxItem>

  <ListBoxItem>MSASCui</ListBoxItem>

  <ListBoxItem>NBService</ListBoxItem>

  <ListBoxItem>SearchFilterHost</ListBoxItem>

  <ListBoxItem>SearchIndexer</ListBoxItem>

  <ListBoxItem>SearchProtocolHost</ListBoxItem>

  <ListBoxItem>services</ListBoxItem>

  <ListBoxItem>sidebar</ListBoxItem>

  <ListBoxItem>SLsvc</ListBoxItem>

  <ListBoxItem>sm56hlpr</ListBoxItem>

  <ListBoxItem>smss</ListBoxItem>

  <ListBoxItem>SMSvcHost</ListBoxItem>

  <ListBoxItem>SMSvcHost</ListBoxItem>

  <ListBoxItem>spmgr</ListBoxItem>

  <ListBoxItem>spoolsv</ListBoxItem>

  <ListBoxItem>sqlservr</ListBoxItem>

  <ListBoxItem>sqlwriter</ListBoxItem>

  <ListBoxItem>StkCSrv</ListBoxItem>

  <ListBoxItem>svchost</ListBoxItem>

  <ListBoxItem>System</ListBoxItem>

  <ListBoxItem>taskeng</ListBoxItem>

  <ListBoxItem>wcourier</ListBoxItem>

  <ListBoxItem>wininit</ListBoxItem>

  <ListBoxItem>winlogon</ListBoxItem>

  <ListBoxItem>WINWORD</ListBoxItem>

  <ListBoxItem>WmiPrvSE</ListBoxItem>

</ListBox>

 

Lo scenario proposto ci ha permesso di osservare un altro possibile utilizzo di LINQ-to-XML in ambito WPF e di apprezzarne, ancora una volta, la grande versatilità. Nei prossimi due capitoli vedremo LINQ in azione in scenari di grande attualità, come le applicazioni Web basate su ASP.NET e SilverLight.

Print | posted on venerdì 19 settembre 2008 21:23 |

Powered by:
Powered By Subtext Powered By ASP.NET