Alessandro Del Sole's Blog

{ A programming space about Microsoft® .NET® }
posts - 1908, 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

Disabilita cookie ShinyStat

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

LINQ & WPF: Creare file di codice XAML e utilizzarne i controlli con VB 2008

LINQ-to-Xml permette di creare e leggere agevolmente qualunque tipo di file a struttura Xml. Da questo concetto non sono esclusi i file .Xaml, che caratterizzano il lato “design” delle applicazioni basate su Windows Presentation Foundation.

 

In questo post vedremo come creare e leggere file .Xaml contenenti definizioni di interfaccia utente WPF, proprio utilizzando LINQ-to-Xml.

 

Lo scopo del gioco è questo: in WPF è possibile creare i cosiddetti FlowDocument, documenti dal contenuto dinamico e riadattabile al variare delle impostazioni dell’interfaccia. Se avete letto il capitolo 6 del mio libro su .NET 3.x, avete avuto modo di vedere in pratica questo tipo di documenti; i FlowDocument sono oggetti WPF e, come tali, definibili via XAML. Il loro contenuto può essere visualizzato, poi, in controlli FlowDocumentReader. Poiché i FlowDocument sono definibili via XAML e poiché è possibile caricare a run-time file di codice XAML (utilizzando la classe System.Windows.Markup.XamlReader) ed utilizzarne i controlli in essi definiti da codice managed, vedremo come creare un’applicazione WPF in grado di ricevere da parte dell’utente elementi come titolo, sottotitolo e testo di un ipotetico documento FlowDocument, che verrà salvato come codice XAML tramite LINQ-to-Xml (sfruttando gli Xml Literals di Visual Basic 2008) e poi ricaricato e mostrato in un FlowDocumentReader mediante la classe XamlReader.

 

La finalità di questo post è quella di illustrare un’altra interessante possibilità di utilizzo di LINQ-to-Xml e come integrarlo con WPF, quindi vi rimando alla documentazione MSDN per approfondimenti sul controllo FlowDocumentReader e i FlowDocument (e, ovviamente, al mio libro J).

 

Ho utilizzato Visual Basic 2008 Express Edition per realizzare l’esempio di codice, di cui alla fine è riportato il LINQ ehm… il link J per il download.

 

Bene, la premessa è stata fin troppo lunga. Create una nuova applicazione WPF (Windows). La finestra sarà suddivisa in tre aree:

 

·         la prima, una riga contenente i pulsanti per salvare e leggere i FlowDocument;

·         la seconda, contenente una serie di Label e TextBox per l’inserimento delle parti principali dell’ipotetico documento, che verrà poi esportato come XAML;

·         la terza, contenente un controllo FlowDocumentReader che utilizzeremo per visualizzare i FlowDocument esportati;

 

Iniziamo a definire l’interfaccia, suddividendo il contenitore Grid, proposto per default, in due parti. Questo il primo XAML:

 

<Grid>

    <Grid.RowDefinitions>

       <RowDefinition/>

       <RowDefinition Height="40"/>

    </Grid.RowDefinitions>

 

Il codice successivo implementa due pulsanti, uno per l’esportazione e uno per il caricamento dei dati:

 

   <StackPanel Grid.Row="1" Orientation="Horizontal"

               HorizontalAlignment="Center">

      <Button Margin="10,5,10,5" Name="ExportAsXaml">Esporta come XAML</Button>

      <Button Margin="10,5,10,5" Name="LoadFromXaml">Carica da XAML</Button>

   </StackPanel>

 

Come ricorderete, il contenitore StackPanel permette di contenere più controlli sulla stessa “linea”, in orizzontale (come nel nostro caso) o in verticale.

Definiamo, ora, un ulteriore StackPanel che conterrà due controlli: un FlowDocumentReader e un Border. Il Border, in particolare, conterrà poi, a sua volta, Label e TextBox. Il FlowDocumentReader:

 

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

    <FlowDocumentReader Name="MyFlowReader" />

 

e il Border:

 

    <Border>

       <StackPanel Orientation="Vertical" Width="485">

           <Label Margin="5,5,5,5">Titolo:</Label>

           <TextBox Margin="5,5,5,5" Name="TitleTextBox"></TextBox>

           <Label Margin="5,5,5,5">Sottotitolo:</Label>

           <TextBox Margin="5,5,5,5" Name="SubTitleTextBox"></TextBox>

           <Label Margin="5,5,5,5">Testo documento:</Label>

           <TextBox Margin="5,5,5,5" AcceptsReturn="True" AcceptsTab="True"

                    Name="DocTextBox" Height="340" TextWrapping="Wrap"/ >

       </StackPanel>

    </Border>

</StackPanel>

 

Ritengo opportune segnalare solamente, vista la semplicità del codice, che le proprietà AcceptsReturn, AcceptsTab e TextWrapping impostano, rispettivamente, la possibilità di andare a capo con Invio, le tabulazioni e il testo a capo automatico.

 

A seguito di queste operazioni, il designer si presenta come in figura:

 

  

Ora viene il divertimento vero e proprio. Fate doppio clic sul pulsante Esporta come XAML, di modo che l’IDE generi automaticamente il relativo gestore di evento. Prima di passare a scrivere codice, facciamo una considerazione. I FlowDocument sono oggetti al cui interno sono nidificati oggetti Paragraph. Ciascun Paragraph rappresenta una porzione di testo che può essere formattata a proprio piacimento, con tanto di figure e collegamenti ipertestuali, gradienti e quant'altro sia possibile sfruttando le nidificazioni di UIElement di WPF. Un piccolo esempio di FlowDocument minimale è il seguente:

 

        <FlowDocument>

            <Paragraph FontSize="24" FontWeight="Bold">

                Esempio di paragrafo in un FlowDocument

            </Paragraph>

        </FlowDocument>

 

Ora, noi abbiamo implementato tre TextBox. Quindi, nel FlowDocument che andremo a creare con LINQ, avremo tre elementi Paragraph. La formattazione di ciascun Paragraph la stabiliremo, per praticità e rapidità illustrativa, direttamente nel codice, anche se potrebbe essere consigliabile permetterne la selezione all’utente. Invece il contenuto di ciascun Paragraph lo scriveremo nel file .Xaml sfruttando le espressioni incorporate (embedded expression) di LINQ-to-Xml. Riporto il codice del gestore dell’evento Click, al termine del quale faremo ulteriori commenti:

 

    Private Sub ExportAsXaml_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles ExportAsXaml.Click

 

        Dim document As XElement = <FlowDocument

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

                                       Name="flowDoc" TextAlignment="Justify"

                                       IsOptimalParagraphEnabled="True"

                                       IsHyphenationEnabled="True"

                                       IsColumnWidthFlexible="True"

                                       ColumnWidth="250"

                                       ColumnGap="20">

 

                                       <Paragraph FontSize="24"

                                           FontWeight="Bold">

                                           <Paragraph.Foreground>

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

                                                   <GradientStop Offset="0" Color="Black"/>

                                                   <GradientStop Offset="0.5" Color="Yellow"/>

                                                   <GradientStop Offset="0.7" Color="White"/>

                                                   <GradientStop Offset="0.8" Color="Yellow"/>

                                                   <GradientStop Offset="1" Color="Black"/>

                                               </LinearGradientBrush>

                                           </Paragraph.Foreground>

                                           <%= TitleTextBox.Text %>

                                       </Paragraph>

 

                                       <Paragraph FontSize="20"

                                           FontWeight="Bold"

                                           Foreground="Chocolate">

                                           <Italic><%= SubTitleTextBox.Text %></Italic>

                                       </Paragraph>

 

                                       <Paragraph FontSize="14" Foreground="Blue">

                                           <%= DocTextBox.Text %>

                                       </Paragraph>

                                   </FlowDocument>

 

        'La conversione in stringa è necessaria per evitare

        'l'aggiunta automatica della dichiarazione Xml (<?xml version="1.0"?>)

        Dim doc As String = document.ToString

 

        'In uno scenario reale si richiede all'utente di specificare il nome del file

        'invece di tecniche di "hard-coding"

        My.Computer.FileSystem.WriteAllText(AppDomain.CurrentDomain.BaseDirectory + "MyFlowDocument.xaml", doc, False)

    End Sub

 

Un file .Xaml non deve necessariamente contenere, come elemento di primo livello, un oggetto Window o un oggetto Page, ma può contenere un qualunque controllo, purché venga specificato il namespace Xml relativo allo schema Microsoft per XAML. Di interessante segnalo la dichiarazione dell’oggetto FlowDocument con assegnazione di alcune proprietà di layout e, nel primo elemento Paragraph, l’utilizzo di un gradiente per il colore di primo piano del testo. In sostanza, con LINQ-to-Xml possiamo scrivere file di codice XAML complessi in modo analogo a come vengono generati dall’IDE. Come poi potete osservare, l’utilizzo delle espressioni incorporate all’interno degli elementi Paragraph permette di attingere al contenuto delle caselle di testo desiderate per specificare il valore degli elementi stessi. Se volete saperne di più sulle espressioni incorporate, potete leggere il mio articolo introduttivo a LINQ-to-Xml su VB T&T.

 

I tag XML sono stati assegnati a un oggetto XElement. Il contenuto di questo oggetto è stato convertito in stringa, prima di essere salvato su file, poiché se usassimo il metodo Save della classe stessa il compilatore aggiungerebbe automaticamente al file la dichiarazione XML, cosa non necessaria in file .Xaml. Per tale motivo abbiamo poi salvato il file utilizzando il metodo WriteAllText della classe My.Computer.FileSystem. Notate come il file venga salvato nella directory ove risiede l’eseguibile, sfruttando la directory corrente dell’AppDomain. Ovviamente, per un test come questo va bene specificare in anticipo il nome del file da scrivere, ma sicuramente è preferibile richiedere all’utente di effettuare la sua scelta.

 

Inserite, poi, le due seguenti direttive in testa al file di codice:

 

Imports System.Windows.Markup

Imports System.IO, System.Xml

 

Il passaggio successivo è quello di implementare il gestore dell’evento Click del pulsante per la lettura del documento. Il codice, commentato al suo interno, è il seguente:

 

    Private Sub LoadFromXaml_Click(ByVal sender As System.Object, ByVal e As _

                System.Windows.RoutedEventArgs) Handles LoadFromXaml.Click

 

      'Istanzia un nuovo stream che punta al file .Xaml da leggere

      Dim xamlStream As New StreamReader(AppDomain.CurrentDomain.BaseDirectory _  

          + "MyFlowDocument.xaml")

 

      'Si lavora in lettura con la classe XmlReader, poichè i file XAML hanno

‘struttura Xml

      Dim reader As XmlReader = XmlReader.Create(xamlStream)

 

      'La classe XamlReader implementa funzionalità di parsing verso fil Xml

      Dim myDocument As FlowDocument = CType(XamlReader.Load(reader), _

          FlowDocument)

 

      'Assegna il contenuto del file .Xaml al FlowDocumentReader

      MyFlowReader.Document = myDocument

    End Sub

 

Intendo dare risalto alle ultime due righe di codice. Nella prima, si dichiara un oggetto FlowDocument che riceve il contenuto del file .Xaml, caricato tramite il metodo Load della classe XamlReader e convertito in FlowDocument. Il controllo FlowDocumentReader predisposto nell’interfaccia riceve, poi, il nuovo oggetto.

 

Non ci resta che avviare l’applicazione. La figura seguente mostra un esempio di inserimento di testo, mostrato dopo essere stato salvato come file di codice XAML tramite LINQ-to-Xml e ricaricato tramite la classe XamlReader:

 

 

 

Mi rendo conto che l’articolo è stato un po’ lungo ma abbiamo imparato alcune cose come:

 

·         esistenza e utilizzo dei documenti FlowDocument in WPF;

·         caricamento a run-time di file di codice XAML tramite Visual Basic;

·         generazione di file di codice XAML tramite LINQ-to-Xml.

 

Il codice completo può essere scaricato da qui:

 

 

Spero che vi sia utile e che sia risultato piacevole J

 

Alessandro

Print | posted on giovedì 5 giugno 2008 22:43 | Filed Under [ Visual Basic Windows Presentation Foundation LINQ ]

Powered by:
Powered By Subtext Powered By ASP.NET