giovedì 24 febbraio 2011

Interfacce grafiche in .NET con il linguaggio XAML



Quando si vogliono realizzare delle applicazioni in .NET con Silverlight, oppure delle presentazioni WPF (Windows Presentation Forms) si ha bisogno di conoscere il linguaggio XAML (eXtensible Application Markup Language). XAML è un linguaggio sviluppato all'interno del .NET Framework, che ci permette di descrivere delle interfacce utente per mezzo di un documento XML in modo schematico.
Quali sono le proprietà e perchè è stato scelto di usare XAML?

  • Come per gli altri linguaggi .NET, XAML viene compilato in codice intermedio (IL).
  • Utilizza grafica vettoriale.
  • Le proprietà di presentazione sono parte del linguaggio (a differenza di XUL che utilizza i CSS). Ciò lo rende più facile da scrivere, ma più difficile da modificare.
  • XAML utilizza le librerie e le classi .NET come un vero e proprio linguaggio del Framework
  • XAML dà possibilità di includere codice C# associato (XUL usa Javascript)
  • Gli eventi sono proprietà dei tag e i tag sono widget.

Le regole di XAML sono semplici:
  • Ciascun elemento di un documento XAML viene mappato ad una classe in .NET (es. Button)
  • Gli elementi hanno una struttura gerarchica in modo tale che gli elementi contengono o sono contenuti da altri elementi (es. Button dentro una Window)
  • Si può accedere alle proprietà “semplici” di una classe per mezzo degli attributi di un elemento (es. Button Content”), oppure, se la proprietà è a sua volta un oggetto, tramite un mappaggio proprietà-elemento (es. Button.Background)

Supponiamo di voler creare un bottone contenuto in una finestra che abbia un certo titolo. In C# scriveremo:

namespace PED.Demo
{
    class Program
    {
        [STAThread]
        static void Main()
        {
            var b = new Button
            {
                Content = "Click Me!"
            };
            var w = new Window
            {
                Title = "XAML Demo",
                Content = b
            };
            var app = new Application();
            app.Run(w);
        }
    }
}


Tale finestra può essere espressa anche in linguaggio XAML:

File MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="XAML Demo" Height="350" Width="525">
       <Grid>
             <Button Content="Click Me!" />   
</Grid>
</Window>

Si noti come sia necessario includere i namespaces di XAML.
La finestra dovrà essere poi inclusa all’interno di un’applicazione:

File App.xaml:
<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        
    </Application.Resources>
</Application>

Questo semplice esempio ci fa capire come le classi in .NET possano essere mappate in XAML e viceversa. E’ possibile anche usare classi custom all’interno di XAML.  Per esempio:

<Window x:Class="WpfApplication1.MainWindow"
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
Title=XAML Demo Height=350 Width=525>
  <StackPanel>
    <Button Content=Click Me! />
    <ListBox>
      <local:Person FirstName=Mario LastName=Rossi />
      <local:Person FirstName=Gino LastName=Bianchi />
    </ListBox>
  </StackPanel>
</Window>


In questo esempio abbiamo inizializzato una classe Person definita localmente e che possiede due proprietà “FirstName” e “LastName”. Implementando il metodo ToString() della classe Person potremo riempire la ListBox con nomi e cognomi. In poche righe di codice C# la classe Person è così definita:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public override string ToString()
    {
        return string.Format("{0} {1}", FirstName, LastName);
    }
}


Per utilizzare XAML dobbiamo creare un progetto in Visual Studio che utilizzi tale linguaggio (per esempio un'applicazione WPF o Silverlight). Una volta creato un nuovo progetto in Visual Studio, tale IDE ci creerà automaticamente lo scheletro dell'applicazione con i file App.xaml  e MainWindow.xaml visti in precedenza, nonchè i file C# (.cs) ad essi collegati (code behind). Realizzare una GUI con XAML/WPF in Visual Studio è del tutto simile a crearne una in Windows Forms o ASP.NET, dato che vi è il "solito" sistema WYSIWYG col drag & drop, affiancato però dal codice XAML.
Si voglia ora per esempio creare un bottone colorato con un certo gradiente: dalla toolbox di VS poniamo un bottone nella MainWindow, analizzando il codice XAML possiamo accedere alle proprietà del bottone come se fossero elementi del documento (VS ci permette di accedere a tali proprietà anche in una finestra separata):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="Click Me!" Height="23"
                HorizontalAlignment="Left"
                Margin="129,36,0,0"
                Name="button1"
                VerticalAlignment="Top"
                Width="75" Click="button1_Click">
            <Button.Background>
                <LinearGradientBrush StartPoint="0.5,0.0" EndPoint="0.5, 1.0">
                    <LinearGradientBrush.GradientStops>
                        <GradientStopCollection>
                            <GradientStop Offset="0" Color="Yellow"/>
                            <GradientStop Offset="0.3" Color="Orange"/>
                            <GradientStop Offset="0.7" Color="Red"/>
                            <GradientStop Offset="1" Color="DarkRed"/>
                        </GradientStopCollection>
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </Button.Background>
        </Button>
    </Grid>
</Window>


Si noti come si definiscono le proprietà del bottone dentro dei tag annidati i cui nomi sono quelli definiti all’interno della classe Button.  Il risultato è un bottone del genere:


Come visto, in XAML gli oggetti possono contenere altri oggetti per cui potremmo pensare di dichiarare allo stesso modo array o collezioni di oggetti:

<x:Array Type="local:Person">
  <local:Person FirstName="Mario" LastName="Rossi" />
  <local:Person FirstName="Gino" LastName="Bianchi" />
</x:Array>

Definisce un array di oggetti Person (x:array è un'estensione di Markup per il supporto alle matrici).
Supponiamo ora di voler collegare l’evento “click” del bottone a del codice C# che visualizzi un messaggio a video.  Cliccando due volte sul bottone dell'anteprima in Visual Studio, verrà creato l'evento button1_Click nel Code Behind associato:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("Click!");
        }
    }

In questo semplice esempio abbiamo visto un modo per utilizzare XAML. In realtà XAML ha diversi “dialetti”: WPF XAML (XAML per WPF), XPS XAML (XAML per descrivere documenti elettronici), Silverlight XAML (subset di XAML per Silverlight), WF XAML (XAML per Windows Workflow Foundation).  XAML ha dei meccanismi quali:


- Markup Extensions: estensioni utilizzate per settare dinamicamente i valori delle proprietà degli oggetti grafici in funzione di altri oggetti esistenti.                               
Vediamo un esempio con una StaticResourceExtension:

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="XAML Demo" Height="350" Width="525">
    <StackPanel>
        <StackPanel.Resources>
            <SolidColorBrush
        x:Key="TextBackBrush"
        Color="LightBlue"
        />
        </StackPanel.Resources>
        <TextBlock Background="{StaticResource TextBackBrush}">Hello!</TextBlock>
    </StackPanel>
</Window>

Questo codice disegnerà la scritta "Hello!" su uno sfondo azzurro chiaro: per cambiare il colore dello sfondo basterà modificare la proprietà Color di SolidColorBrush. Ci sono altri modi per creare delle MarkupExtension, ma tralascerò per ora questo argomento.

- Attached Properties: sono delle proprietà che si possono applicare a più controlli differenti, ma la cui definizione è data a livello di classe. Inoltre permettono di creare proprietà “virtuali” che di fatto estendono quelle già presenti in una certa classe. La sintassi da usare è AttachedPropertyProvider.PropertyName.
Per esempio:

<DockPanel>
  <CheckBox DockPanel.Dock="Top">Hello</CheckBox>
</DockPanel>
    DockPanel.Dock è una proprietà valida per tutti gli oggetti DockPanel. Si noti come il concetto è simile alle proprietà statiche delle classi: in C# questo può essere descritto per esempio con:


    DockPanel.SetDock(myCheckBox, Dock.Top);


    2 commenti:

    elisa rubino ha detto...

    la prima parte dell'articolo è illeggibile...

    Andrea Cacciarru ha detto...

    Cosa non ti è chiaro?

    Posta un commento

    Recent Posts

     
    Design by Free WordPress Themes | Bloggerized by Lasantha - Premium Blogger Themes | cna certification