Introduzione a XAML con Silverlight

Silverlight: introduzione a XAML

Extensible Application Markup Language (XAML - pronunciato "zammel") è un linguaggio derivato da XML usato per definire oggetti e le loro proprietà e metodi tipicamente usati per costruire un'interfaccia utente. XAML è stato reso popolare dal suo utilizzo nel Windows Presentation Foundation (WPF) usato per definire l'interfaccia utente di Windows Vista. XAML è stato creato da Microsoft e introdotto nella versione 3.0 del .NET Framework e può esser utilizzato per definire grafica e animazioni 2D e 3D.

Gli elementi dichiarati in XAML generalmente rappresentano oggetti esistenti nel .NET Framework. XAML viene usato molto spesso non solo nel contesto di WPF ma anche in Silverlight. Quando viene letto un file XAML, il parser instanzia gli oggetti del .NET Framework corrispondenti agli elementi dichiarati nel file XAML. Gli attributi degli elementi in genere rappresentano le proprietà di un oggetto. Si consideri il seguente frammento di codice XAML:

      

Il codice soprastante viene usato per definire un TextBlock in una finestra WPF. Quando il parser XAML incontra quest'elemento, crea un'istanza della classe System.Windows.Controls.TextBlock. Tale classe viene usata per mostrare una certa quantità di contenuti, quali testo e labels. Nell'esempio mostrato prima, l'oggetto TextBlock contiene un elemento Run che accomoda la formattazione del testo contenuto. Gli attributi di TextBlock e Run vengono dichiarati per settare le loro proprietà. Il codice XAML mostrato sopra produce la finestra mostrata qui sotto.

XAML
Fig 1: risultato del codice XAML appena visto

Così come per altre tecnologie del .NET Framework, potete creare documenti XAML usando un qualsiasi text editor e potete interpretare e manipolare il codice XAML attraverso un qualsiasi linguaggio di programmazione. WPF è ottimizzato per leggere, interpretare ed eseguire documenti XAML.

Si tenga a mente quando si lavora con XAML che:

  • XAML è un linguaggio basato su XML, quindi è case-sensitive. Nella maggior parte dei casi, gli oggetti definiti in XAML devono corrispondere ad oggetti e proprietà realmente esistenti;
  • Così come per XML, gli spazi bianchi in XAML vengono considerati come un singolo spazio;
  • Tutti i documenti XML devono avere un singolo elemento radice. Tale elemento per i file XAML, quando utilizzati nel contesto di WPF, dovrebbe essere o <Window> oppure <Page>, a seconda del tipo di applicazione che si sta creando (per Silverlight vale <Canvas>).


Sintassi alternativa per gli attributi

L'implementazione XAML illustrata nell'esempio precedente è la più semplice e maggiormente utilizzata per l'assegnamento di valori agli attributi. Ad ogni modo quando si utilizza un linguaggio basato su XML, i valori dei dati estesi possono esser definiti sia tramite gli attributi oppure attraverso dei sottoelementi. Il comportamento prestabilito per XAML prevede la definizione delle proprietà degli oggetti attraverso gli attributi e questo metodo funziona egregiamente per semplici valori. Ad ogni modo, alcune proprietà richiedono valori più complessi , come oggetti figli oppure una proprietà potrebbe avere valori multipli. In questo scenario, un semplice attributo non è sufficiente.

Nella determinazione del metodo appropriato, tenete a mente il modello relazionale per i database, in particolare le regole di normalizzazione. XML viene usato per memorizzare dati. Se XML, e in questo caso XAML, è concepito con le regole della normalizzazione in mente, le relazioni fra oggetti e relative proprietà dovrebbero adattarsi bene a XAML.


La sintassi degli elementi delle proprietà

Quando sviluppate in XML, avendo in mente i principi di progettazione dei database relazionali, un attributo tipicamente corrisponde ad una colonna in una tabella e questa è una correlazione logica. La seconda forma normale nella normalizzazione di un database relazionale, secondo il Dr. Codd, specifica che non devono esserci gruppi di attributi ridondanti e multivalore. Trasferendo questo concetto in XML, nessun attributo dovrebbe contenere valori multipli. Se sono necessari valori multipli per una certa proprietà di un oggetto, tali valori dovrebbero essere identificati attraverso l'uso di elementi addizionali invece di attributi.

Quando vengono usati degli elementi per identificare valori di certe proprietà in XAML, ci si riferisce alla sintassi di "proprietà dell'elemento". Inoltre, ogni valore delle proprietà dichiarato attraverso la sintassi che fa uso degli attributi dovrebbe essere in grado di usare anche la sintassi appena esposta, sebbene sia raro il contrario.

A titolo esemplificativo, il codice XAML usato per definire lo sfondo della finestra WPF vista sopra utilizza la sintassi che fa uso delle proprietà degli elementi.

<Window.Background>    <LinearGradientBrush EndPoint="1,0.5"  StartPoint="0,0.5" SpreadMethod="Pad"><GradientStop Color="#FF495B24" Offset="0"/><GradientStop Color="#FFB4C397" Offset="0.416"/>    </LinearGradientBrush></Window.Background>

 

<a href="iframe_xaml1.html" title="Vedi esempio">Vedi esempio</a>;

 

Nel codice mostrato qui sopra lo sfondo della finestra potrebbe essere opzionalmente dichiarato attraverso un attributo come . Ad ogni modo si consideri meglio il codice. Come potrebbe un singolo valore di un attributo riassumere i parametri maggiormente complessi di LinearGradientBrush? Non è possibile, quiondi per accomodare adeguatamente i valori di proprietà avanzate, i valori dovrebbero essere espressi attraverso dei sottolementi piuttosto che attraverso attributi come visto in precedenza.


Estensioni del linguaggio markup

Quando si creando documenti XAML, si tenga a mente che il parser XAML crea istanze degli oggetti quando incontra gli elementi nel documento. In molti scenari, il comportamento di default del parser potrebbe comportare un uso non ottimale della memoria. Ad esempio, nella definizione degli stili, dietro le quinte, viene creato un oggetto Style per mantenere le informazioni degli stili. Tali informazioni generalmente saranno condivise da altri oggetti nell'interfaccia utente. Specificando le informazioni sullo stile a livello di elemento per ogni oggetti dell'interfaccia, comporterà la creazione di molti oggetti che manterranno le medesime informazioni. Si consumerebbero molte meno risorse creando un singolo oggetto Style e condividendolo con gli altri oggetti semplicemente riferendosi ad esso. In aggiunta, l'informazione sugli stili potrebbe essere gestita ed aggiornata molto più facilmente se fosse definita in un unico luogo invece che in posti diversi.

La soluzione per una gestione ottimizzata della memoria è la dichiarazione di un oggetto Style globale o condiviso. Una risorsa condivisa può esser riferita da altri oggetti attraverso le estensioni del linguaggio markup. Tali estensioni consentono di definire un valore di un attributo come un riferimento ad una risorsa condivisa. Ci sono molti tipi di estensioni, fra le quali le più comuni sono Binding Markup Extension usata nel collegamento dei dati, la Static Resource Markup Extension usata per riferire risorse condivise statiche (risorse dichiarate e disponibili a tempo di compilazione) e la Dynamic Resource Markup Extension, usata per riferirsi a risorse dcondivise dinamiche (risorse disponibili a tempo d'esecuzione).

Un riferimento ad un'estensione markup viene delimitata dalle parentesi graffe. L'esempio sottostante illustra i colori dello sfondo utilizzati come risorse della finestra e riferiti come estensioni markup a risorse dinamiche.

<Window.Resources>   <Color x:Key="myGreenColor">#FFB4C397</Color>   <Color x:Key="myDarkGreenColor">#FF495B24</Color>  </Window.Resources>  <Window.Background>   <LinearGradientBrush EndPoint="1,0.5"StartPoint="0,0.5"SpreadMethod="Pad">    <GradientStop Color="{DynamicResource myDarkGreenColor}" Offset="0"/>    <GradientStop Color="{DynamicResource myGreenColor}" Offset="0.431"/>   </LinearGradientBrush></Window.Background>

Il documento XAML completo usato per generare la finestra nella figura mostrata sopra viene presentato nel listato sottostante.

Es. 1: Windows1.xaml

<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="MyFantasyPicks.Window1"Title="Fantasy League Manager 2008"Height="216"Width="529"x:Name="DisplayMyPicks"xmlns:d="http://schemas.microsoft.com/expression/blend/2006"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">   <Window.Resources>    <Color x:Key="myGreenColor">#FFB4C397</Color>    <Color x:Key="myDarkGreenColor">#FF495B24</Color>   </Window.Resources>   <Window.Background>    <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5" SpreadMethod="Pad">     <GradientStop Color="{DynamicResource myDarkGreenColor}" Offset="0"/>     <GradientStop Color="{DynamicResource myGreenColor}" Offset="0.431"/>    </LinearGradientBrush>   </Window.Background><Grid>    <TextBlock Margin="10,10,0,0" VerticalAlignment="Top"    FontFamily="Segoe UI" Text="Welcome to the Fantasy League Manager" />    <Path Margin="15,30,15,0" VerticalAlignment="Top" Height="0.5"    Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" Data="M19,32 L469,33" />    <Button HorizontalAlignment="Left" Margin="15,41,0,0" VerticalAlignment="Top"Width="189" Height="23" Content="Display My Picks" x:Name="btnDisplayPicks"Click="btnDisplayPicks_Click">     <Button.Background><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFF3F3F3" Offset="0.005"/> <GradientStop Color="#FFEBEBEB" Offset="0.44"/> <GradientStop Color="#FFDDDDDD" Offset="0.531"/> <GradientStop Color="#FFDAB925" Offset="0.904"/></LinearGradientBrush>     </Button.Background>    </Button>    <Path x:Name="pMiddle" Margin="15,73.5,15,0" VerticalAlignment="Top"    Height="0.5" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000"    Data="M19,32 L469,33" Visibility="Visible" />    <TextBox x:Name="txtPicks" Margin="15,78,15,0" VerticalAlignment="Top" Height="63" Text="" TextWrapping="Wrap" Background="#FFB4C397" FontFamily="Segoe UI" FontSize="11" FontWeight="Normal"/> <Path x:Name="pBottom" Margin="15,0,15,33.5" VerticalAlignment="Bottom" Height="0.5" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" Data="M19,32 L469,33" d:LayoutOverrides="VerticalAlignment"/>    <TextBlock x:Name="tbFooter" Margin="15,150,15,0" VerticalAlignment="Top"   Height="21" Text="copyright 2007. fantasy league manager"   TextWrapping="Wrap" FontSize="11" FontWeight="Normal" FontFamily="Segoe UI"/>   </Grid>  </Window>

 

<a href="iframe_xaml3.html" title="Vedi esempio">Vedi esempio</a>;

 


I namespace XAML

I documenti XAML creati attraverso i tool Microsoft tipicamente conterranno due dichiarazioni di spazio dei nomi. La prima dichiarazione sarà il namespace di default, cioè xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation", un riferimento diretto al framework WPF. La seconda dichiarazione, generalmente identificata da un prefisso con la "x" , come xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml", è un riferimento allo standard XAML e dovrebbe esistere in tutti i documenti XAML. Ad ogni modo il primo namespace potrebbe differire a seconda della tecnologia che utilizza XAML.


Gli eventi

I documenti XAML sono costruiti attorno la medesima architettura di base come per i documentio ASP.NET (Web forms, Web services, Web user controls, ecc). Questi documenti hanno del codice associato ai file. Un documento XAML è un documento testuale che contiene markup XAML. Il codice alla base del file è un file associato che contiene classi, proprietà, metodi, ecc in un particolare linguaggio di programmazione compatibile con .NET Framework e che viene usato per gestire gli eventi inizializzati dagli oggetti dichiarati nel markup XAML. Il codice alla base dei file è generalmente compilato in un assembly .NET e viene associato ai documenti XAML attraverso l'attributo x:Class nell'elemento root del file XAML.

Nell'esempio precedente, l'attributo x:Class identifica la classe Window1 nel namespace MyFantasyPicks come classe che gestirà gli eventi inizializzati dagli oggetti nel file XAML Window1.


Eventi orientati

Gli elementi XAML sono correlati agli oggetti del .NET Framework. Tali oggetti sono totalmente orentati agli oggetti. Una loro caratteristica è che definiscono il comportamento, generalmente definito attraverso delle funzioni membri. La funzione membro più comune è un metodo. I metodi agiscono attraverso il linguaggio di programmazione per mezzo di funzioni e subroutine. Un metodo può essere invocato direttamente da una porzione di codice o può essere identificato comefunzionalità che va eseguita in risposta ad un particolare evento utente. Il più comune evento utente in un'interfaccia grafica è il click del mouse sugli elementi dell'interfaccia stessa.

A qualsiasi elemento che sia correlato ad un oggetto .NET Framework il quale contenga un particolare evento, può essere assegnato un handler per gestire l'evento. Ad esempio un elemento XAML Button è correlato ad un oggetto Button del .NET Framework. Quest'ultimo contiene l'evento OnClick, quindi il corrispondente elemento XAML può assegnare un handler per gestire l'evento click come mostrato nel codice qui sotto:

<Button   Click="btnDisplayPicks_Click"   HorizontalAlignment="Left"   Margin="15,41,0,0"   VerticalAlignment="Top"   Width="189"   Height="23"   Content="Display My Picks"   x:Name="btnDisplayPicks" />

Il gestore dell'evento associato, btnDisplayPicks_Click, risiede nel codice alla base del file. In quest'esempio, il codice è scritto in C#. L'handler apre il file XML e mostra i dati.

Es 2: Window1.xaml.cs

using System;using System.Collections.Generic;  using System.Linq;  using System.Text;  using System.Windows;  using System.Windows.Controls;  using System.Windows.Data;  using System.Windows.Documents;  using System.Windows.Input;  using System.Windows.Media;  using System.Windows.Media.Imaging;  using System.Windows.Navigation;  using System.Windows.Shapes;  using System.Xml;    namespace MyFantasyPicks  {/// <summary>/// Interaction logic for Window1.xaml/// </summary>public partial class Window1 : Window  {public Window1()  {  InitializeComponent();}    /// <summary>    /// This method opens the XML file and displays the stored picks.    /// </summary>    /// <param name="sender"></param>    /// <param name="e"></param>    private void btnDisplayPicks_Click(object sender, RoutedEventArgs e)  {    // Create an XMLDocument object.  XmlDocument xmlDoc = new XmlDocument();    // Load the XML file.  xmlDoc.Load(@"FantasyPick.xml");  // We should have error handling  // and more elaborate code in here  // but this works for an example.  // Reference the first pick element.  XmlAttributeCollection pickElementAttributes = xmlDoc.DocumentElement.FirstChild.Attributes;  XmlNodeList pickElementChildren = xmlDoc.DocumentElement.FirstChild.ChildNodes;    // Display my picks.  txtPicks.Text = "My fantasy picks for week number " + pickElementAttributes[0].Value + " are:";    // Iterate through the picks.  for (int i = 0; i < pickElementChildren.Count; i++)  {  txtPicks.Text +=  pickElementChildren[i].Attributes[0].Value +  " playing " + pickElementChildren[i].Attributes[1].Value +  "";  }    // Clean up.  pickElementChildren = null;  pickElementAttributes = null;  xmlDoc = null;    }}}

 

<a href="iframe_xaml4.html" title="Vedi esempio">Vedi esempio</a>;

 

una pratica comune nello sviluppo di un iterfaccia utente è la dichiarazione di un handler degli eventi centralizzato nell'oggetto contenitore che gestirà gli eventi per tutti i sottoelementi di tale oggetto. Tale pratica richiede un oggetto contenitore per implementare il gestore degli eventi. Ad esempio, un handler centralizzato per la gestione dei click potrebbe esser creato a livello di finestra. A causa del comportamento a cascata degli eventi, gli eventi click per tutti i controlli contenuti nei sottolementi saranno gestiti a livello di finestra. Ciò è possibile perché l'oggetto Windows implementa un handler per gli eventi.

I controlli e gli oggetti in XAML sono stati ottimizzati in maniera tale che gli oggetti contenitori abbiano al loro interno pochi handler degli eventi. Ad ogni modo, ogni oggetto di XAML potrebbe scatenare un evento contenuto in un altro oggetto. In particolare, un oggetto contenitore può facilmente scatenare eventi di oggetti contenuti al suo interno anche se esso non implementa direttamente l'evento. questo comportamento è possibile attraverso il eventi orientati in XAML.

Un evento orientato è una chiamata ad un evento che può essere girata attraverso un oggettoseparato dall'oggetti che contiene l'evento. Quando un oggetto contenitore dichiara un evento orientato per i suoi sottoelementi, come StackPanel che gestisce gli eventi Click per gli elementi figli contenuti negli oggetti Button, la dichiarazione viene fatta a livello dell'oggetto contenitore e il tipo di oggetti peri l quale l'evento viene gestito qualifica il nome dell'evento. Nell'esempio sottostante, StackPanel contiene un oggetto Button. StackPanel non implementa l'evento Click, ad ogni modo StackPanel gestisce i click del mouse per tutti gli oggetti Button contenuti, dichiarando Button.Click come vento orientato.

<StackPanel Button.Click="Button_ClickHandler" >    <Button HorizontalAlignment="Left" Margin="15,41,0,0" VerticalAlignment="Top"Width="189" Height="23" Content="Display My Picks" x:Name="btnDisplayPicks">     <Button.Background><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFF3F3F3" Offset="0.005"/> <GradientStop Color="#FFEBEBEB" Offset="0.44"/> <GradientStop Color="#FFDDDDDD" Offset="0.531"/> <GradientStop Color="#FFDAB925" Offset="0.904"/></LinearGradientBrush>     </Button.Background>    </Button>  </StackPanel>

 

<a href="iframe_xaml5.html" title="Vedi esempio">Vedi esempio</a>;

 

Il codice completo del documento XAML associato all'handler visto prima è mostrato qui sotto.

Es 3: Window1.xaml

<Windowxmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"x:Class="MyFantasyPicks.Window1"Title="Fantasy League Manager 2008" Height="216" Width="529"x:Name="DisplayMyPicks" xmlns:d="http://schemas.microsoft.com/expression/blend/2006"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">   <Window.Resources>    <Color x:Key="myGreenColor">#FFB4C397</Color>    <Color x:Key="myDarkGreenColor">#FF495B24</Color>   </Window.Resources>   <Window.Background>    <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5" SpreadMethod="Pad">     <GradientStop Color="{DynamicResource myDarkGreenColor}" Offset="0"/>     <GradientStop Color="{DynamicResource myGreenColor}" Offset="0.431"/>    </LinearGradientBrush>   </Window.Background><Grid>    <TextBlock Margin="10,10,0,0" VerticalAlignment="Top" FontFamily="Segoe UI"   Text="Welcome to the Fantasy League Manager" />    <Path Margin="15,30,15,0" VerticalAlignment="Top" Height="0.5" Fill="#FFFFFFFF"    Stretch="Fill" Stroke="#FF000000" Data="M19,32 L469,33" />    <Button HorizontalAlignment="Left" Margin="15,41,0,0" VerticalAlignment="Top"Width="189" Height="23" Content="Display My Picks" x:Name="btnDisplayPicks"Click="btnDisplayPicks_Click">     <Button.Background><LinearGradientBrush EndPoint="0,1" StartPoint="0,0"> <GradientStop Color="#FFF3F3F3" Offset="0.005"/> <GradientStop Color="#FFEBEBEB" Offset="0.44"/> <GradientStop Color="#FFDDDDDD" Offset="0.531"/> <GradientStop Color="#FFDAB925" Offset="0.904"/></LinearGradientBrush>     </Button.Background>    </Button>    <Path x:Name="pMiddle" Margin="15,73.5,15,0" VerticalAlignment="Top"    Height="0.5" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000"    Data="M19,32 L469,33" Visibility="Visible" />    <TextBox x:Name="txtPicks" Margin="15,78,15,0" VerticalAlignment="Top" Height="63" Text="" TextWrapping="Wrap" Background="#FFB4C397" FontFamily="Segoe UI" FontSize="11" FontWeight="Normal"/> <Path x:Name="pBottom" Margin="15,0,15,33.5" VerticalAlignment="Bottom" Height="0.5" Fill="#FFFFFFFF" Stretch="Fill" Stroke="#FF000000" Data="M19,32 L469,33" d:LayoutOverrides="VerticalAlignment"/>    <TextBlock x:Name="tbFooter" Margin="15,150,15,0" VerticalAlignment="Top"   Height="21" Text="copyright 2007. fantasy league manager"   TextWrapping="Wrap" FontSize="11" FontWeight="Normal"   FontFamily="Segoe UI"/>   </Grid></Window>

 

<a href="iframe_xaml6.html" title="Vedi esempio">Vedi esempio</a>;

 

Il form WPF risultante dall'esempio appena visto, viene mostrato qui sotto: il testo viene mostrato al di sotto del pulsante una volta che questo viene cliccato.

WPF form
Fig 2: Form WPF reso da Windows1.xaml

Strumenti per XAML

Il codice XAML creato qui sopra è stato sviluppato attarverso tool Microsoft, ad ogni modo per via della popolarità di XAML, ci sono molti editor di terze parti. Gli editor principali sono Visual Studio 2008, Expression Blend e XAMLPad.