Cenni preliminari su XAML

Aggiornamento: novembre 2007

In questo argomento vengono descritte le funzionalità del linguaggio Extensible Application Markup Language (XAML) e viene illustrata la modalità di utilizzo di XAML per la scrittura di applicazioni Windows Presentation Foundation (WPF). Nell'argomento viene descritto in modo specifico il linguaggio XAML implementato da Windows Presentation Foundation (WPF). XAML costituisce un concetto di linguaggio più ampio rispetto a Windows Presentation Foundation (WPF).

Nel presente argomento sono contenute le seguenti sezioni.

  • Un linguaggio dichiarativo con supporto del controllo del flusso
  • Elementi oggetto di XAML
  • Impostazione delle proprietà
  • Valori di riferimento ed estensioni di markup
  • Valori dell'attributo con supporto TypeConverter
  • Tipi di insieme e proprietà degli insiemi XAML
  • Proprietà di contenuto XAML
  • Maiuscolo e minuscolo e spazi vuoti in XAML
  • Ulteriori informazioni sulla sintassi XAML
  • Elementi radice XAML e spazi dei nomi XML
  • Eventi e code-behind XAML
  • x:Name
  • Proprietà ed eventi associati
  • Classi di base e XAML
  • Sicurezza XAML
  • Caricamento di XAML dal codice
  • Argomenti successivi
  • Argomenti correlati

Un linguaggio dichiarativo con supporto del controllo del flusso

XAML semplifica la creazione di un'interfaccia utente per il modello di programmazione .NET Framework. È possibile infatti creare elementi dell'interfaccia utente visibili nel markup XAML dichiarativo e quindi separare la definizione dell'interfaccia utente dalla logica di runtime utilizzando file code-behind uniti al markup tramite definizioni di classe parziali. La capacità di combinare il codice con il markup in XAML è importante in quanto XML è dichiarativo per natura e non suggerisce un modello per il controllo del flusso. Un linguaggio dichiarativo basato su XML è molto intuitivo per la creazione di interfacce che variano da prototipo a produzione, specialmente per le persone con una certa esperienza in progettazione e tecnologie Web. A differenza di altri linguaggi di markup, XAML rappresenta direttamente la creazione di istanze di oggetti gestiti. Questo principio di progettazione generale consente l'accesso di codice semplificato e di debug per gli oggetti creati in XAML.

I file XAML sono file che in genere presentano l'estensione .xaml.

Nell'esempio XAML seguente viene mostrato come sia necessaria una quantità minima di markup per creare un pulsante di un'interfaccia utente. Il pulsante creato presenta un aspetto visivo predefinito tramite stili dei temi e comportamenti predefiniti mediante la progettazione delle relative classi.

<StackPanel>
  <Button Content="Click Me"/>
</StackPanel>

Elementi oggetto di XAML

In XAML è incluso un insieme di regole per l'esecuzione del mapping degli elementi oggetto a classi o strutture, degli attributi a proprietà o eventi e degli spazi dei nomi XML agli spazi dei nomi CLR. Gli elementi XAML eseguono il mapping ai tipi Microsoft .NET definiti negli assembly a cui si fa riferimento, mentre gli attributi eseguono il mapping ai membri di tali tipi.

Nell'esempio precedente sono specificati due elementi oggetto: <StackPanel> (con un tag di chiusura) e <Button/> (che dispone di molti attributi; gli attributi sono discussi in una sezione successiva). Ciascuna delle stringhe StackPanel e Button esegue il mapping al nome di una classe che è definita da WPF ed è parte degli assembly WPF. Quando si specifica un tag dell'elemento oggetto, viene creata un'istruzione che consente all'elaborazione XAML di creare una nuova istanza della classe denominata nel momento in cui la pagina XAML viene caricata. Ciascuna istanza viene creata chiamando il costruttore predefinito della classe o della struttura sottostante e archiviando il risultato. Affinché possa essere utilizzata come elemento oggetto in XAML, la classe o struttura deve esporre un costruttore pubblico predefinito (senza parametri).

Impostazione delle proprietà

Le proprietà di XAML vengono impostate definendo le proprietà di un elemento oggetto tramite una varietà di sintassi possibili. Le sintassi che sarà possibile utilizzare per una determinata proprietà varieranno in base alle caratteristiche della proprietà che si imposta.

L'impostazione dei valori di proprietà consente di aggiungere funzionalità o caratteristiche agli elementi oggetto. Lo stato iniziale dell'istanza dell'oggetto sottostante per un elemento oggetto si basa sul comportamento predefinito del costruttore. In genere, l'applicazione utilizzerà un elemento diverso da un'istanza completamente predefinita di un dato oggetto.

Sintassi per attributi

In XAML, le proprietà spesso possono essere espresse come attributi. La sintassi per attributi è la sintassi per l'impostazione delle proprietà più semplice e risulterà molto intuitiva per gli sviluppatori che hanno utilizzato linguaggi di markup in passato. Nel markup seguente, ad esempio, viene creato un pulsante che presenta un testo rosso e uno sfondo blu oltre a un testo visualizzato specificato come Content.

<Button Background="Blue" Foreground="Red" Content="This is a button"/>

Sintassi per elementi proprietà

Per alcune proprietà di un elemento oggetto, la sintassi per attributi non può essere utilizzata in quanto l'oggetto o le informazioni necessarie per fornire il valore di proprietà non possono essere espresse adeguatamente come semplice stringa. In questi casi, è possibile utilizzare una sintassi diversa, nota come sintassi per elementi proprietà, che consente di impostare la proprietà dell'elemento contenitore a cui si fa riferimento con il contenuto del tag. In genere, il contenuto è un oggetto del tipo accettato dalla proprietà come valore (con l'istanza di impostazione del valore specificata di solito come un altro elemento oggetto). La sintassi per elementi proprietà è <NomeTipo.Proprietà>. Dopo avere specificato un contenuto, è necessario chiudere l'elemento proprietà con un tag di chiusura come avviene con qualsiasi altro elemento (con sintassi </NomeTipo.Proprietà>). Per le proprietà che supportano sia la sintassi per elementi proprietà, sia quella per elementi attributo, le due sintassi in genere hanno lo stesso risultato, sebbene sottigliezze quali la gestione degli spazi vuoti possano variare leggermente nei due casi. Se supportata, la sintassi per attributi di solito è più conveniente e consente un markup più compatto; tuttavia si tratta unicamente di una questione di stile, non di una limitazione tecnica. Nell'esempio seguente vengono mostrate le stesse proprietà impostate nell'esempio di sintassi per attributi precedente, tuttavia questa volta viene utilizzata la sintassi per elementi proprietà per tutte le proprietà dell'oggetto Button.

<Button>
  <Button.Background>
    <SolidColorBrush Color="Blue"/>
  </Button.Background>
  <Button.Foreground>
    <SolidColorBrush Color="Red"/>
  </Button.Foreground>
  <Button.Content>
    This is a button
  </Button.Content>
</Button>

La sintassi degli elementi proprietà per XAML si allontana notevolmente dall'interpretazione XML di base del markup. Per XML, la sintassi <NomeTipo.Proprietà> rappresenta un altro elemento, che non implica necessariamente una relazione a un elemento padre TypeName oltre a essere un elemento figlio. In XAML, la sintassi <NomeTipo.Property> implica direttamente che Property è una proprietà di NomeTipo, in quanto impostata dal contenuto dell'elemento proprietà, e che non vi sarà mai un elemento con un nome simile, ma discreto, con un punto all'interno del nome.

Proprietà ed ereditarietà delle classi

Le proprietà visualizzate come attributi XAML in un elemento WPF spesso vengono ereditate dalle classi di base. Nell'esempio precedente, ad esempio, la proprietà Background non è una proprietà dichiarata immediatamente nella classe Button, se si analizzano la definizione della classe, i risultati della reflection o la documentazione. Invece, Background è ereditata dalla classe Control di base.

Il comportamento dell'ereditarietà delle classi degli elementi XAML di WPF rappresenta un altro allontanamento significativo dall'interpretazione XML di base del markup. L'ereditarietà delle classi (in particolare se le classi di base intermedie sono astratte) è una delle ragioni per le quali l'insieme di elementi XAML e dei relativi attributi consentiti è difficile da rappresentare con precisione e completezza utilizzando i tipi di schema che in genere sono impiegati per la programmazione XML, ad esempio il formato DTD o XSD. La "X" di XAML inoltre significa "estensibile" e l'estensibilità preclude la completezza di qualsiasi rappresentazione specificata di ciò che XAML rappresenta per WPF, sebbene la scelta di mantenere definizioni degli spazi dei nomi XML distinte possa essere utile per risolvere questo problema; questo concetto verrà illustrato in una sezione successiva.

Valori di riferimento ed estensioni di markup

Le estensioni di markup sono un concetto di XAML. Nella sintassi per attributi, le parentesi graffe ({e}) indicano l'utilizzo di un'estensione di markup. Consentono infatti di indicare all'elaborazione XAML di non trattare i valori dell'attributo come valore di stringa letterale oppure come valore che è possibile convertire direttamente in stringa.

Quando le proprietà accettano un valore del tipo di riferimento, spesso richiedono una sintassi per elementi proprietà (che crea sempre un'istanza nuova) oppure un riferimento all'oggetto tramite un'estensione di markup. L'utilizzo di un'estensione di markup può restituire un'istanza esistente e pertanto essere più versatile o potrebbe incorrere in un overhead minore dell'oggetto.

Quando per fornire un valore dell'attributo si utilizza un'estensione di markup, il valore dell'attributo deve essere fornito invece dalla logica all'interno della classe di supporto per l'estensione di markup rilevante. Le estensioni di markup maggiormente utilizzate nella programmazione di applicazioni WPF sono Binding, utilizzata per le espressioni di associazione dati e i riferimenti alle risorse StaticResource e DynamicResource. Le estensioni di markup consentono di utilizzare la sintassi dell'attributo per fornire valori di riferimento per le proprietà, anche se una determinata proprietà non supporta una sintassi dell'attributo per la creazione diretta di istanze dell'oggetto o consente un comportamento specifico che posticipa il comportamento generale del requisito che prevede la compilazione delle proprietà XAML con i valori del tipo della proprietà.

Nell'esempio seguente, il valore della proprietà Style viene impostato utilizzando la sintassi per attributi. La proprietà Style accetta un'istanza della classe Style, un tipo di riferimento che per impostazione predefinita non è stato possibile specificare all'interno di una stringa di sintassi per attributi. Tuttavia, in questo caso l'attributo fa riferimento a una particolare estensione di markup, StaticResource. Quando quell'estensione di markup viene elaborata, restituisce un riferimento a uno stile del quale in precedenza è stata creata un'istanza come risorsa con chiave in un dizionario di risorse.

<Page.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
  <Style TargetType="Border" x:Key="PageBackground">
    <Setter Property="Background" Value="Blue"/>
  </Style>


...


</Page.Resources>
<StackPanel>
  <Border Style="{StaticResource PageBackground}">


...


  </Border>
</StackPanel>

Le risorse costituiscono semplicemente un utilizzo dell'estensione di markup attivato da WPF o da XAML. Per un elenco di riferimento delle estensioni di markup, vedere Estensioni XAML degli spazi dei nomi WPF o Funzionalità del linguaggio dello spazio dei nomi XAML (x:). Per ulteriori informazioni sulle estensioni di markup, vedere Estensioni di markup e XAML.

Valori dell'attributo con supporto TypeConverter

Nella sezione relativa alla sintassi per attributi è stata affermata la necessità che il valore dell'attributo possa essere impostato tramite una stringa. La gestione di base, nativa del modo in cui le stringhe vengono convertite in altri tipi di oggetto o valori primitivi si basa sul tipo String stesso. Molti tipi WPF o membri di tali tipi, tuttavia, estendono il comportamento di elaborazione dell'attributo della stringa di base in modo che le istanze di tipi di oggetto più complessi possano essere specificate come valori dell'attributo tramite una stringa. A livello di codice, questa elaborazione viene ottenuta specificando un convertitore di tipo CLR che elabora il valore dell'attributo della stringa. Il tipo di struttura Thickness, utilizzato in genere per indicare le misure di un'area rettangolare Margin, è un esempio di un tipo che presenta una speciale sintassi per attributi con supporto TypeConverter esposta per tutte le proprietà che accettano quel tipo, al fine di offrire semplicità di utilizzo nel markup XAML. Nell'esempio seguente viene utilizzata una sintassi per attributi con supporto TypeConverter per fornire un valore per un oggetto Margin:

<Button Margin="10,20,10,30" Content="Click me"/>

L'esempio precedente di sintassi per attributi è equivalente all'esempio di sintassi più dettagliato riportato di seguito, in cui Margin è impostato invece tramite la sintassi per elementi proprietà contenente un elemento oggetto Thickness e quattro proprietà chiave di Thickness sono impostate come attributi nella nuova istanza:

<Button Content="Click me">
  <Button.Margin>
    <Thickness Left="10" Top="20" Right="10" Bottom="30"/>
  </Button.Margin>
</Button>

Sebbene l'utilizzo della sintassi con supporto TypeConverter o di una sintassi equivalente più dettagliata sia in genere una scelta di stile di codificazione, il primo tipo di sintassi garantisce un markup più semplice. Tuttavia, esiste un numero limitato di oggetti per i quali il convertitore dei tipi rappresenta l'unica modalità possibile per impostare una proprietà per quel tipo, in quanto lo stesso oggetto tipo non dispone di un costruttore predefinito. Un esempio è il seguente: Cursor.

Per ulteriori informazioni sulla modalità di supporto della sintassi per attributi con supporto TypeConverter, vedere TypeConverter e XAML.

Tipi di insieme e proprietà degli insiemi XAML

XAML specifica una funzionalità di linguaggio mediante la quale l'elemento oggetto che rappresenta un tipo di insieme può essere omesso intenzionalmente dal markup. Quando un processore XAML gestisce una proprietà che accetta un tipo di insieme, un'istanza del tipo di insieme adatto viene creata implicitamente, anche se l'elemento oggetto per quell'insieme non è presente nel markup. Nelle pagine di riferimento dell'SDK per i tipi di insieme, questa sintassi con l'omissione intenzionale dell'elemento oggetto per un insieme si nota occasionalmente nella sezioni di sintassi XAML come sintassi per insiemi implicita.

Questo tipo di sintassi è disponibile per i tipi che implementano IList o IDictionary oppure per le matrici.

Un esempio di sintassi per insiemi implicita è già stato fornito, senza essere menzionato, nell'esempio relativo alle risorse XAML:

<Page.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
  <Style TargetType="Border" x:Key="PageBackground">
    <Setter Property="Background" Value="Blue"/>
  </Style>


...


</Page.Resources>
<StackPanel>
  <Border Style="{StaticResource PageBackground}">


...


  </Border>
</StackPanel>

Fatta eccezione per l'elemento radice, ogni elemento oggetto in una pagina, nidificato come elemento figlio di un altro elemento rappresenta in realtà uno o entrambi i casi seguenti: un membro di una proprietà dell'insieme implicita del relativo elemento padre o un elemento che specifica il valore della proprietà di contenuto XAML per l'elemento padre (le proprietà di contenuto XAML saranno discusse in una sezione successiva). In altre parole, la relazione tra gli elementi padre e gli elementi figlio in una pagina di markup in realtà è un singolo oggetto nella radice; ogni elemento oggetto al di sotto della radice è una singola istanza che fornisce un valore di proprietà del padre oppure uno degli elementi all'interno di un insieme che è anche un valore della proprietà del tipo di insieme del padre. Nel caso dell'esempio delle risorse, la proprietà Resources accetta un oggetto di tipo ResourceDictionary. Nell'esempio seguente viene illustrata la sintassi equivalente con l'elemento oggetto per ResourceDictionary specificato in modo esplicito.

<Page.Resources>
  <ResourceDictionary>
      <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
      <Style TargetType="Border" x:Key="PageBackground">
        <Setter Property="Background" Value="Blue"/>
      </Style>


...


  </ResourceDictionary>
</Page.Resources>
<StackPanel>
  <Border Style="{StaticResource PageBackground}">


...


    </Border>
  </StackPanel>
</Page>

L'insieme Resources è un esempio di proprietà dell'insieme presente in molti elementi comuni a livello di framework WPF. L'impostazione di questa proprietà in XAML richiede la sintassi per elementi proprietà. Ogni elemento oggetto incluso all'interno dell'elemento proprietà diventa un elemento dell'insieme, ovvero un'implementazione di IDictionary. Sebbene il tipo di insieme stesso in genere disponga di una proprietà o di un indicizzatore contenente gli elementi, tale proprietà non può essere specificata nel markup, ma viene indicata in modo completamente implicito. Per ResourceDictionary quella proprietà rappresenta l'indicizzatore Item.

Per un esempio più esaustivo di utilizzo del dizionario di risorse, vedere Procedura: definire e fare riferimento a una risorsa.

Proprietà di contenuto XAML

XAML specifica una funzionalità di linguaggio mediante la quale una qualsiasi classe che può essere utilizzata come elemento oggetto XAML può indicare esattamente una delle relative proprietà in modo che sia la proprietà di contenuto XAML per le istanze della classe. Quando un processore XAML gestisce un elemento oggetto che dispone di una proprietà di contenuto XAML, tutti gli elementi XML figlio di tale elemento oggetto vengono elaborati come se fossero contenuti all'interno di un tag di elemento proprietà implicito che rappresenta la proprietà di contenuto. All'interno del markup, la sintassi degli elementi proprietà per la proprietà di contenuto XAML può essere omessa. Tutti gli elementi figlio specificati nel markup diventano il valore della proprietà di contenuto XAML.

Un esempio di proprietà di contenuto XAML, seppure senza essere richiamata è stato già fornito nel primo esempio di questo argomento.

<StackPanel>
  <Button Content="Click Me"/>
</StackPanel>

In questo caso, Button è un elemento figlio di StackPanel. Si tratta di un markup semplice e intuitivo nel quale vengono omessi due tag per due ragioni diverse.

  • Elemento proprietà StackPanel.Children omesso: StackPanel deriva da Panel. Panel definisce Panel.Children come relativa proprietà di contenuto XAML. Tutte le classi derivate di Panel dispongono pertanto di tale proprietà di contenuto XAML e l'elemento proprietà per Panel.Children può essere omesso.

  • Elemento oggetto UIElementCollection omesso: la proprietà Panel.Children accetta il tipo UIElementCollection, che implementa IList. Pertanto, il tag dell'elemento oggetto UIElementCollection può essere omesso, in base alle regole definite da XAML per gli insiemi. In questo caso, in realtà non è possibile creare un'istanza di UIElementCollection come elemento oggetto. Non è nemmeno possibile dichiarare in modo esplicito quell'oggetto Collection, in quanto UIElementCollection non espone un costruttore predefinito. Anche altri tipi di insieme WPF non espongono costruttori per l'utilizzo dell'elemento oggetto, poiché la gestione della sintassi XAML per insiemi consente in ogni caso di utilizzarli in XAML in modo implicito. È questo il motivo per il quale l'elemento oggetto UIElementCollection viene mostrato con i commenti nell'esempio; in caso di assenza di commenti, non sarebbe possibile compilare l'esempio.

<StackPanel>
  <StackPanel.Children>
    <!--<UIElementCollection>-->
    <Button>
      <Button.Content>
        Click Me
      </Button.Content>
    </Button>
    <!--</UIElementCollection>-->
  </StackPanel.Children>
</StackPanel>

Testo interno e proprietà di contenuto XAML

Per l'esempio StackPanel / Button è possibile un'ulteriore variazione.

<StackPanel>
  <Button>Click Me</Button>
</StackPanel>

Notare la modifica nel modo in cui viene specificato il testo visualizzato per Button. La proprietà Content è stata specificata in precedenza nella sintassi per attributi; in questo caso la stringa visualizzata è il testo interno di un elemento oggetto Button. Questa sintassi funziona in quanto Content è la proprietà di contenuto XAML della classe di base ButtonContentControl. La stringa all'interno dell'elemento viene valutata in base al tipo di proprietà della proprietà Content, vale a dire Object. Object non effettua alcun tentativo di conversione del tipo di stringa, pertanto il valore della proprietà Content diventa il valore della stringa letterale. In alternativa, il contenuto all'interno di Button avrebbe potuto essere qualsiasi oggetto Object. Controlli quali Button in genere definiscono la proprietà di contenuto XAML per la classe in modo che tale proprietà possa essere utilizzata per il testo dell'interfaccia utente e quello visualizzato, per la composizione del controllo o per entrambi.

La capacità di posizionare le stringhe all'interno dell'elemento come contenuto al fine di produrre un markup simile agli altri linguaggi di markup comuni è particolarmente importante per il modello di documento dinamico (per informazioni dettagliate, vedere Documenti di Windows Presentation Foundation) e per la localizzazione (vedere Globalizzazione per Windows Presentation Foundation).

I valori delle proprietà di contenuto XAML devono essere contigui

Il valore di una proprietà di contenuto XAML deve essere fornito completamente prima o completamente dopo qualsiasi altro elemento proprietà dell'elemento oggetto. Tale requisito è vero sia se il valore di una proprietà di contenuto XAML è specificato come stringa, sia se è specificato come uno o più oggetti. Ad esempio, il markup seguente non viene compilato:

<Button>I am a 
  <Button.Background>Blue</Button.Background>
  blue button</Button>

Questa situazione non è consentita perché se questa sintassi fosse esplicita mediante l'utilizzo della sintassi per elementi proprietà per la proprietà di contenuto, la proprietà di contenuto sarebbe impostata due volte:

<Button>
  <Button.Content>I am a </Button.Content>
  <Button.Background>Blue</Button.Background>
  <Button.Content> blue button</Button.Content>
</Button>

Un esempio simile è rappresentato dal caso in cui la proprietà di contenuto è un insieme e gli elementi figlio sono inframmezzati con elementi proprietà:

<StackPanel>
  <Button>This example</Button>
  <StackPanel.Resources>
    <SolidColorBrush x:Key="BlueBrush" Color="Blue"/>
  </StackPanel.Resources>
  <Button>... is illegal XAML</Button>
</StackPanel>

Modelli di contenuto

Una classe potrebbe supportare un utilizzo come elemento XAML in termini di sintassi, tuttavia quell'elemento funzionerà correttamente in un'applicazione o in una pagina solo quando viene collocato in una posizione prevista di un modello di contenuto globale o di una struttura ad albero dell'elemento. Ad esempio, un oggetto MenuItem deve essere posizionato in genere solo come un figlio di una classe derivata MenuBase quale Menu. I modelli di contenuto per elementi specifici sono documentati come parte delle note nelle pagine relative alle classi per i controlli e le altre classi WPF che possono essere utilizzate come elementi XAML. Per alcuni controlli che dispongono di modelli di contenuto più complessi, il modello di contenuto è documentato come argomento concettuale separato. Vedere Modelli di contenuto.

Maiuscolo e minuscolo e spazi vuoti in XAML

In XAML viene applicata la distinzione tra maiuscole e minuscole. Gli elementi oggetto, gli elementi proprietà e i nomi di attributo devono essere specificati tutti utilizzando correttamente le maiuscole e le minuscole quando si esegue il confronto del nome con il nome del tipo sottostante nell'assembly o con il nome di un membro di un tipo. Non sempre per i valori degli attributi viene effettuata la distinzione tra maiuscole e minuscole. Tale distinzione per i valori dipenderà dal comportamento del convertitore dei tipi associato alla proprietà che accetta il valore o al tipo di valore della proprietà. Ad esempio, le proprietà che accettano il tipo Boolean possono accettare true o True come valori equivalenti, ma solo perché la conversione del tipo della stringa predefinita per Boolean accetta già tali valori come equivalenti.

Processori e serializzatori XAML ignorano oppure eliminano tutti gli spazi vuoti non significativi e normalizzano gli spazi vuoti significativi. Questo comportamento in genere è l'unica conseguenza quando si specificano delle stringhe all'interno delle proprietà di contenuto XAML. In termini più semplici, in XAML i caratteri di spazio, avanzamento riga e tabulazione vengono convertiti in spazi e lo spazio rilevato a una delle estremità di una stringa contigua viene conservato. La spiegazione completa della gestione degli spazi vuoti di XAML non viene fornita in questo argomento. Per informazioni dettagliate, vedere Elaborazione degli spazi vuoti in XAML.

Ulteriori informazioni sulla sintassi XAML

La sintassi per insiemi implicita e le proprietà di contenuto XAML sono entrambe funzionalità del linguaggio XAML che consentono l'omissione di determinati tag derivati. Lo scopo di queste funzionalità consiste nel rendere più visibili le relazioni padre-figlio degli elementi di una pagina al momento della creazione o dell'esame del markup.

Per ulteriori informazioni sulla sintassi per attributi e sulla sintassi per elementi proprietà, nonché sugli altri termini utilizzati nella descrizione della sintassi XAML in tutta la documentazione SDK, vedere Terminologia della sintassi XAML. Inoltre, l'argomento Terminologia della sintassi XAML rappresenta un buon punto di partenza se si prendono in considerazione gli utilizzi di XAML da consentire quando si crea una classe personalizzata.

Elementi radice XAML e spazi dei nomi XML

In un file XAML deve essere incluso un solo elemento radice, perché possa essere considerato un file XML di formato corretto e un file XAML valido. In genere, è necessario scegliere un elemento che faccia parte del modello dell'applicazione, ad esempio Window o Page per una pagina, ResourceDictionary per un dizionario esterno o Application per la radice della definizione dell'applicazione. Nell'esempio riportato di seguito viene illustrato l'elemento radice di un file XAML standard per una pagina WPF, con l'elemento radice Page.

<Page
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"


...


</Page>

L'elemento radice inoltre contiene gli attributi xmlns e xmlns:x, che indicano a un processore XAML quali sono gli spazi dei nomi XML contenenti le definizioni dell'elemento per gli elementi a cui il markup farà riferimento. L'attributo xmlns indica in modo specifico lo spazio dei nomi XML predefinito. All'interno dello spazio dei nomi XML predefinito, gli elementi oggetto del markup possono essere specificati senza un prefisso. Per la maggior parte degli scenari di applicazione di WPF e per quasi tutti gli esempi forniti nelle sezioni dell'SDK dedicate a WPF, il mapping dello spazio dei nomi XML WPF predefinito viene eseguito allo spazio dei nomi https://schemas.microsoft.com/winfx/2006/xaml/presentation. L'attributo xmlns:x indica uno spazio dei nomi XML aggiuntivo che esegue il mapping dello spazio dei nomi https://schemas.microsoft.com/winfx/2006/xaml del linguaggio XAML. I componenti del linguaggio necessari definiti dalla specifica XAML sono preceduti dal prefisso x: quando utilizzati come riferimento nel markup di un file con questo mapping. Tale utilizzo di xmlns per la definizione di un ambito di utilizzo e di mapping è coerente con la specifica XML 1.0. Si noti che gli attributi xmlns sono strettamente necessari solo nell'elemento radice di ciascuna pagina e nella definizione dell'applicazione, se fornita nel markup. Le definizioni xmlns saranno applicate a tutti gli elementi figlio della radice; tale comportamento è ancora una volta coerente con la specifica XML 1.0 per xmlns. Gli attributi xmlns sono inoltre consentiti in altri elementi al di sotto della radice e vengono applicati a tutti gli elementi figlio dell'elemento di definizione. Tale utilizzo è tuttavia insolito, in quanto la definizione o ridefinizione frequente degli spazi dei nomi XML può comportare uno stile di markup XAML di difficile lettura.

È noto che gli assembly WPF contengono i tipi che supportano i mapping WPF allo spazio dei nomi XML predefinito dal momento che la configurazione fa parte del file di compilazione del progetto. Il mapping degli assembly viene eseguito anche nei file delle destinazioni. Pertanto, l'esecuzione del mapping di xmlns rappresenta tutto quanto necessario per fare riferimento agli elementi XAML provenienti da assembly WPF. Per gli assembly personalizzati o per gli assembly esterni a WPF, è possibile specificare l'assembly come parte del mapping xmlns. Di solito viene scelto un prefisso diverso, tuttavia è anche possibile scegliere uno spazio dei nomi diverso come predefinito ed eseguire quindi il mapping di WPF a un prefisso. Per ulteriori informazioni sulla modalità di correlazione tra gli spazi dei nomi XML e gli spazi dei nomi del codice di supporto negli assembly, vedere Spazi dei nomi XAML e mapping dello spazio dei nomi.

Prefisso x:

Nell'esempio dell'elemento radice precedente, il prefisso x: è stato utilizzato per eseguire il mapping dello spazio dei nomi XML https://schemas.microsoft.com/winfx/2006/xaml XAML. Il prefisso x: verrà utilizzato per eseguire il mapping dello spazio dei nomi XAML nei modelli per i progetti, negli esempi e nella documentazione in tutto il presente SDK. Nel prefisso x: o nello spazio dei nomi XML XAML sono presenti diversi costrutti di programmazione che verranno utilizzati abbastanza di frequente nella sintassi XAML. Di seguito viene fornito un elenco dei costrutti di programmazione più comuni del prefisso x: o dello spazio dei nomi XAML che verranno utilizzati:

  • x:Key: imposta una chiave univoca per ciascuna risorsa in un oggetto ResourceDictionary. x:Key rappresenterà probabilmente il 90% degli usi di x: che saranno osservati nel markup dell'applicazione.

  • x:Class: specifica lo spazio dei nomi CLR e nome della classe per la classe che fornisce code-behind per una pagina XAML. È necessario che tale classe supporti il code-behind ed è per questa ragione che quasi sempre viene eseguito il mapping di x:, anche se non sono presenti delle risorse.

  • x:Name: specifica il nome di un oggetto di runtime per l'istanza presente nel codice di esecuzione dopo l'elaborazione di un elemento oggetto. Per i casi di denominazione di elementi in cui la proprietà Name a livello di framework WPF equivalente non è supportata si utilizza x:Name. Tale situazione si verifica in determinati scenari di animazione.

  • x:Static: attiva il riferimento a un valore che ottiene un valore statico che non è una proprietà compatibile con XAML. 

  • x:Type: crea un riferimento Type basato sul nome di un tipo. È utilizzato per specificare attributi che accettano Type, ad esempio Style.TargetType, sebbene in molti casi la proprietà disponga di una conversione nativa da stringa a Type che rende facoltativo l'utilizzo di x:Type.

Nel prefisso x: o nello spazio dei nomi XAML sono presenti costrutti di programmazione aggiuntivi non comuni. Per informazioni dettagliate, vedere Funzionalità del linguaggio dello spazio dei nomi XAML (x:).

Eventi e code-behind XAML

La maggior parte delle applicazioni WPF include un markup e un code-behind. All'interno di un progetto, la sintassi XAML viene scritta come file .xaml, mentre per scrivere un file code-behind si utilizza un linguaggio CLR, ad esempio Microsoft Visual Basic .NET o C#. Al momento della compilazione di un file XAML, il percorso del file code-behind XAML per ciascuna pagina XAML viene identificato specificando uno spazio dei nomi e una classe come attributo x:Class dell'elemento radice della pagina XAML.

Negli esempi riportati fino a questo momento sono stati illustrati molti pulsanti, nessuno dei questi era associato a un comportamento logico. Il meccanismo primario a livello di applicazione per l'aggiunta di un comportamento per un elemento oggetto consiste nell'utilizzo di un evento esistente della classe dell'elemento e nella scrittura di un gestore specifico per quell'evento che viene richiamato nel momento in cui l'evento viene generato in fase di esecuzione. Il nome dell'evento e il nome del gestore da utilizzare sono specificati nel markup, mentre il codice che implementa il gestore è definito nel code-behind.

<Page 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="MyNamespace.MyPageCode">
  <Button Click="ClickHandler" >Click Me!</Button>
</Page>
namespace MyNamespace
{
  public partial class MyPageCode
  {
    void ClickHandler(object sender, RoutedEventArgs e)
    {
      Button b = e.Source as Button;
      b.Background = Brushes.Red;
    }
  }
}

Notare che il file code-behind utilizza lo spazio dei nomi CLR MyNamespace e dichiara MyPageCode come classe parziale all'interno di tale spazio dei nomi. Questo è parallelo al valore dell'attributo x:Class di MyNamespace.MyPageCode fornito nella radice del markup. Il compilatore crea automaticamente una classe parziale per ogni pagina XAML compilata, derivando una classe dal tipo di elemento radice. Quando si fornisce code-behind che definisce anche la stessa classe parziale, il codice risultante viene combinato all'interno dello stesso spazio dei nomi e della stessa classe dell'applicazione compilata.

Per ulteriori informazioni sui requisiti per la programmazione del code-behind, vedere la sezione di Code-behind e XAML relativa al code-behind, al gestore eventi e ai requisiti delle classi parziali.

Se non si desidera creare un file code-behind separato, è anche possibile rendere il codice inline all'interno di un file XAML. Tuttavia, il codice inline è una tecnica meno versatile che presenta limitazioni sostanziali. Per informazioni dettagliate, vedere Code-behind e XAML.

Sintassi per attributi dell'evento

Quando si specifica il comportamento tramite gli eventi all'interno del markup, in genere si utilizza la sintassi per attributi per associare i gestori. L'elemento oggetto nel quale viene specificato l'attributo dell'evento diventa l'istanza che resta in ascolto dell'evento e chiama il gestore. Il nome dell'evento specifico che si desidera gestire è il nome dell'attributo. Il valore dell'attributo è il nome del metodo del gestore che viene definito. Successivamente è necessario fornire l'implementazione del gestore in code-behind, con il gestore basato sul delegato per quell'evento. Per la scrittura del gestore in code-behind si utilizza un linguaggio di programmazione quale Microsoft Visual Basic .NET o C#.

Per ogni evento WPF verranno segnalati dei dati al momento della generazione dell'evento. I gestori eventi possono accedere a questi dati evento. Nell'esempio precedente, il gestore ottiene l'origine evento segnalata tramite i dati evento, quindi imposta le proprietà per tale origine.

Eventi indirizzati

Un evento indirizzato è una particolare funzionalità evento, univoca e fondamentale per WPF. Gli eventi indirizzati consentono a un elemento di gestire un evento generato da un elemento diverso, se gli elementi sono connessi tramite una relazione di struttura ad albero dell'elemento. Quando si specifica la gestione degli eventi con un attributo XAML, l'evento indirizzato può essere ascoltato e gestito da qualsiasi elemento, inclusi quelli che non presentano quel particolare evento nella tabella dei membri della classe. Ciò è possibile qualificando l'attributo del nome evento con il nome della classe di appartenenza. Ad esempio, l'elemento padre StackPanel nell'esempio StackPanel / Button potrebbe registrare un gestore per l'evento Click del pulsante dell'elemento figlio specificando l'attributo Button.Click nell'elemento oggetto StackPanel, con il nome del gestore come valore dell'attributo. Per ulteriori informazioni, vedere Cenni preliminari sugli eventi indirizzati.

x:Name

Per impostazione predefinita, l'istanza dell'oggetto creata mediante l'elaborazione di un elemento oggetto non possiede un identificatore univoco o un riferimento implicito all'oggetto che è possibile utilizzare nel codice. Se si chiama un costruttore nel codice, quasi sempre il risultato del costruttore viene utilizzato per impostare una variabile sull'istanza creata, in modo che sia possibile fare riferimento all'istanza in un secondo momento nel codice. Per fornire l'accesso standardizzato agli oggetti creati tramite una definizione del markup, la sintassi XAML definisce l'attributo x:Name. È possibile impostare il valore dell'attributo x:Name in qualsiasi elemento oggetto. All'interno del code-behind, l'identificatore scelto è equivalente a una variabile dell'istanza che fa riferimento all'istanza costruita. Gli elementi denominati funzionano sotto ogni aspetto come istanze dell'oggetto (il nome fa riferimento appunto all'istanza) e il code-behind può fare riferimento agli elementi denominati per gestire le interazioni di runtime all'interno dell'applicazione.

Gli elementi XAML a livello di framework WPF ereditano una proprietà Name che è equivalente all'attributo x:Name definito da XAML. Altre classi forniscono equivalenti a livello di proprietà per x:Name, che in genere viene definito anche come proprietà Name. Da un punto di vista generale, se non è possibile trovare una proprietà Name nella tabella dei membri dell'elemento scelto, utilizzare invece x:Name.

Nell'esempio seguente, viene impostata la proprietà Name per un elemento StackPanel. Quindi un gestore di un Button all'interno di StackPanel fa riferimento a StackPanel tramite il relativo riferimento all'istanza buttonContainer impostato da Name.

<StackPanel Name="buttonContainer">


...


  <Button Click="RemoveThis">Click to remove this button</Button>
</StackPanel>
void RemoveThis(object sender, RoutedEventArgs e)
{
    FrameworkElement fe = e.Source as FrameworkElement;
    if (buttonContainer.Children.Contains(fe))
    {
        buttonContainer.Children.Remove(fe);
    }
}

Come accade per una variabile, il nome di un'istanza è governato da un concetto di ambito, per cui è possibile attivare nomi che siano univoci all'interno di un determinato ambito prevedibile. Il markup primario che definisce una pagina indica un namescope univoco, nel quale il limite è l'elemento radice di quella pagina. Tuttavia, altre origini di markup possono interagire con una pagina in fase di esecuzione, ad esempio gli stili o i modelli all'interno degli stili e tali origini di markup spesso dispongono di namescope non necessariamente connessi con il namescope della pagina. Per ulteriori informazioni su x:Name e sui namescope, vedere Name, Attributo x:Name, o Ambiti dei nomi WPF.

Proprietà ed eventi associati

XAML specifica una funzionalità di linguaggio che consente di definire determinate proprietà o eventi per qualsiasi elemento, indipendentemente dall'esistenza della proprietà o dell'elemento all'interno della tabella dei membri dell'elemento per il quale è impostata. La versione delle proprietà di questa funzionalità è denominata proprietà associata, la versione degli eventi è denominata evento associato. Dal punto di vista concettuale, è possibile pensare alle proprietà e agli eventi associati come a membri globali che possono essere impostati in qualsiasi classe o elemento, indipendentemente dalla gerarchia di classi.

In XAML, le proprietà associate vengono in genere utilizzate tramite la sintassi dell'attributo. In questa sintassi, una proprietà associata viene specificata nel formato TipoProprietario.NomeProprietà. In apparenza, assomiglia all'utilizzo di un elemento proprietà, tuttavia in questo caso il TipoProprietario che si specifica è sempre un tipo diverso rispetto all'elemento oggetto nel quale è impostata la proprietà associata. TipoProprietario è il tipo che fornisce i metodi della funzione di accesso richiesti da un processore XAML per ottenere o impostare il valore della proprietà associata. Lo scenario più comune per le proprietà associate consiste nel consentire agli elementi figlio di segnalare un valore di proprietà al relativo elemento padre.

Nell'esempio seguente viene illustrata la proprietà associata DockPanel.Dock. La classe DockPanel definisce le funzioni di accesso per DockPanel.Dock e pertanto possiede la proprietà associata. La classe DockPanel include inoltre la logica che scorre i relativi elementi figlio e verifica in modo specifico in ogni elemento la presenza di un valore impostato di DockPanel.Dock. Se individuato, quel valore viene utilizzato durante il layout per posizionare gli elementi figlio. L'utilizzo della proprietà associata DockPanel.Dock e questa funzionalità di posizionamento rappresentano infatti lo scenario opportuno per la classe DockPanel.

<DockPanel>
  <Button DockPanel.Dock="Left" Width="100" Height="20">I am on the left</Button>
  <Button DockPanel.Dock="Right" Width="100" Height="20">I am on the right</Button>
</DockPanel>

In Windows Presentation Foundation (WPF), tutte le proprietà associate sono inoltre implementate come proprietà di dipendenza. Per informazioni dettagliate, vedere Cenni preliminari sulle proprietà associate.

Gli eventi associati utilizzano un formato di sintassi per attributi TipoProprietario.NomeEvento simile. Come per gli eventi non associati, il valore dell'attributo per un evento associato in XAML specifica il nome del metodo di gestione richiamato quando l'evento viene gestito per l'elemento. 

Uno scenario in cui si utilizzano gli eventi associati è quello relativo agli eventi di input del dispositivo che possono essere gestiti per qualsiasi elemento, ad esempio i pulsanti del mouse. Un esempio di evento associato di questo tipo è Mouse.MouseDown. Tuttavia, la maggior parte degli elementi a livello di framework WPF possono utilizzare questo evento senza utilizzare l'evento associato. Ciò è possibile in quanto la classe dell'elemento di base UIElement crea un alias per l'evento associato Mouse.MouseDown e lo espone nella tabella dei membri UIElement (come MouseDown). Di conseguenza, in genere non è necessario specificare la sintassi di un evento associato in una pagina XAML o nella programmazione dell'applicazione Windows Presentation Foundation (WPF). Le eccezioni sono rappresentate dall'utilizzo di elementi personalizzati o di elementi oggetto che non derivano da UIElement ma che continuano a disporre di una rappresentazione visiva (caso raro). In WPF, tutti gli eventi associati vengono inoltre implementati come eventi indirizzati. ContentElement espone inoltre alias per gli eventi di input, che possono essere utilizzati dal modello del documento dinamico. Per informazioni dettagliate, vedere Cenni preliminari sugli eventi indirizzati e Cenni preliminari sull’input.

Anatomia di un elemento radice della pagina XAML

Nella tabella seguente viene mostrato un elemento radice standard della pagina XAML frammentato, in cui sono visualizzati gli attributi specifici di un elemento radice identificati in questo argomento:

<Page

Apertura dell'elemento oggetto dell'elemento radice

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

Lo spazio dei nomi predefinito (WPF)

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

Lo spazio dei nomi XAML

x:Class="MyNamespace.MyPageCode"

La dichiarazione di classe parziale che connette il markup a un qualsiasi code-behind definito in questa stessa classe parziale

>

Fine dell'elemento oggetto per la radice, non ancora chiuso perché la pagina contiene elementi figlio

Classi di base e XAML

L'XAML sottostante e i relativi schemi sono un insieme di classi che corrispondono agli oggetti CLR e agli elementi del markup da utilizzare in XAML. Tuttavia non è possibile eseguire il mapping di tutte le classi agli elementi. Le classi astratte, ad esempio ButtonBase e determinate classi di base non astratte sono utilizzate per l'ereditarietà nel modello a oggetti CLR e non supportano i tag di markup XAML corrispondenti. Le classi base, incluse quelle astratte, continuano a essere importanti per lo sviluppo XAML in quanto ciascuno degli elementi XAML concreti eredita i membri da una classe base nella relativa gerarchia. Spesso tali membri includono proprietà che possono essere impostate come attributi per l'elemento oppure eventi che possono essere gestiti. FrameworkElement è la classe base concreta dell'interfaccia utente di WPF a livello di framework WPF. Durante la progettazione dell'interfaccia utente, si utilizzano diverse classi Shape, Panel, Decorator oppure Control, che derivano tutte da FrameworkElement. Una classe di base correlata, FrameworkContentElement, supporta elementi orientati al documento utili per una presentazione del layout di flusso, mediante le API che eseguono il mirroring delle API in FrameworkElement. La combinazione di attributi a livello di elemento e di un modello a oggetti CLR fornisce un insieme di proprietà comuni che è possibile impostare nella maggior parte degli elementi XAML concreti, indipendentemente dal tipo di elemento esatto e dalla relativa classe sottostante.

Sicurezza XAML

XAML è un linguaggio di markup che rappresenta in modo diretto la creazione di istanze dell'oggetto e la relativa esecuzione. Gli elementi creati in XAML hanno pertanto la stessa possibilità di interagire con le risorse di sistema (accesso alla rete e IO file system, ad esempio) del codice equivalente generato.

WPF supporta la Protezione per l'accesso al codice (CAS, Code Access Security) del framework di sicurezza .NET. Di conseguenza, il contenuto WPF in esecuzione nell'area Internet dispone di autorizzazioni di esecuzione ridotte. In quest'area Internet in genere viene eseguito il codice "XAML separato", vale a dire pagine di XAML non compilato interpretato in fase di caricamento da parte di un visualizzatore XAML, e l'applicazione browser XAML (XBAP), che utilizzano lo stesso set di autorizzazioni. Tuttavia, il codice XAML caricato in un'applicazione completamente attendibile dispone dello stesso accesso alle risorse di sistema dell'applicazione host. Per ulteriori informazioni, vedere Sicurezza con attendibilità parziale di Windows Presentation Foundation.

Caricamento di XAML dal codice

Sebbene XAML possa essere utilizzato per definire un'intera interfaccia utente, talvolta è opportuno impiegarlo per definirne solo una parte. Questa funzionalità potrebbe essere utilizzata per consentire la personalizzazione parziale, l'archiviazione locale di informazioni, utilizzando XAML per fornire un oggetto business o una varietà di possibili scenari. La chiave per questi scenari è la classe XamlReader e il relativo metodo Load. L'input è un file XAML e l'output è un oggetto che rappresenta l'intera struttura ad albero di runtime degli oggetti creata da quel markup. È possibile quindi inserire l'oggetto in modo che sia una proprietà di un altro oggetto già esistente nell'applicazione. Se la proprietà è una proprietà adatta nel modello di contenuto che dispone di funzionalità di visualizzazione e che notifica al motore di esecuzione che è stato aggiunto un nuovo contenuto nell'applicazione, il contenuto di un'applicazione in esecuzione può essere modificato in modo abbastanza semplice, caricando XAML. Notare che questa funzionalità in genere è disponibile solo nelle applicazioni con attendibiltà completa, a causa delle ovvie implicazioni di sicurezza del caricamento di file all'interno delle applicazioni in esecuzione.

Argomenti successivi

In questo argomento viene fornita un'introduzione di base ai concetti e alla terminologia della sintassi XAML. Per ulteriori informazioni sui termini utilizzati in questo argomento, vedere Terminologia della sintassi XAML.

In alternativa, provare l'esercitazione Guida introduttiva a Windows Presentation Foundation. Al momento dell'effettiva creazione dell'applicazione di markup descritta dall'esercitazione, l'esercizio consentirà di rafforzare molti dei concetti descritti in questo argomento.

WPF utilizza un particolare modello dell'applicazione basato sulla classe Application. Per informazioni dettagliate, vedere Cenni preliminari sulla gestione di applicazioni.

In Compilazione di un'applicazione WPF vengono forniti maggiori dettagli sulla modalità di compilazione di applicazioni che includono XAML dalla riga di comando e mediante Microsoft Visual Studio.

In Cenni preliminari sulle proprietà di dipendenza vengono fornite ulteriori informazioni sulla versatilità delle proprietà in Windows Presentation Foundation (WPF) e viene introdotto il concetto di proprietà di dipendenza.

Infine, nell'SDK è incluso uno strumento di modifica XAML denominato XAMLPad. Tale strumento può essere utilizzato per la sperimentazione in tempo reale di XAML.

Vedere anche

Concetti

XAMLPad

XAML e classi personalizzate

Cenni preliminari sugli elementi di base

Strutture ad albero in WPF

Altre risorse

Funzionalità del linguaggio dello spazio dei nomi XAML (x:)

Estensioni XAML degli spazi dei nomi WPF

Modelli di contenuto