Cenni preliminari su XAML (WPF)

In questo argomento vengono descritte le funzionalità del linguaggio XAML e viene illustrato come utilizzare XAML per la scrittura di applicazioni Windows Presentation Foundation (WPF). In particolare, viene descritto il linguaggio XAML implementato in WPF. Il linguaggio XAML in quanto tale, tuttavia, rappresenta un concetto di linguaggio più ampio rispetto a quello implementato in WPF.

Nel presente argomento sono contenute le seguenti sezioni.

  • Definizione di XAML
  • Cenni sulla sintassi XAML
  • Maiuscolo e minuscolo e spazi vuoti in XAML
  • Estensioni di markup
  • Convertitori di tipi
  • Elementi radice XAML e spazi dei nomi XAML
  • Prefissi personalizzati e tipi personalizzati in XAML
  • Eventi e code-behind XAML
  • Elementi denominati XALM
  • Proprietà ed eventi associati
  • Tipi di base e XAML
  • Sicurezza XAML
  • Caricamento di XAML dal codice
  • Fasi successive
  • Argomenti correlati

Definizione di XAML

XAML è un linguaggio di markup dichiarativo Applicato al modello di programmazione .NET Framework, XAML semplifica la creazione di un'UI per un'applicazione .NET Framework. È possibile creare elementi di UI visibili nel markup XAML dichiarativo, quindi separare la definizione di UI dalla logica di runtime utilizzando file code-behind, uniti al markup tramite definizioni di classe parziali. XAML rappresenta in modo diretto la creazione di istanze di oggetti in un set specifico di tipi di supporto definiti in assembly. In ciò si differenzia dalla maggior parte degli altri linguaggi di markup, che sono in genere linguaggi interpretati senza un legame diretto con il sistema di tipi di supporto. XAML consente un flusso di lavoro in cui parti distinte possono operare nell'UI e nella logica di un'applicazione, utilizzando strumenti potenzialmente diversi.

Se rappresentati come testo, i file XAML sono file XML in genere con estensione .xaml. I file possono essere codificati tramite qualsiasi codifica XML, tuttavia la codifica tipica è UTF-8.

Nell'esempio seguente viene illustrato come creare un pulsante come parte di un'UI. L'esempio non deve essere ritenuto esaustivo e ha il semplice scopo di fornire un'idea molto generale del modo in cui XAML rappresenta metafore di programmazione dell'UI comuni.

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

Cenni sulla sintassi XAML

Nelle sezioni seguenti vengono descritte le forme di base della sintassi XAML e viene fornito un breve esempio di markup. L'obiettivo di queste sezioni non consiste nel fornire informazioni complete su ogni forma di sintassi, ad esempio sulla modalità di rappresentazione di queste sintassi nel sistema di tipi di supporto. Per ulteriori informazioni sulle specifiche della sintassi XAML per ognuna delle forme di sintassi introdotte in questo argomento, vedere Descrizione dettagliata della sintassi XAML.

Se si ha familiarità con il linguaggio XML, la maggior parte del materiale incluso in alcune delle sezioni successive risulterà di facile comprensione. Ciò è dovuto a uno dei principi di base della progettazione XAML. Il linguaggio XAML definisce concetti propri, tuttavia questi concetti funzionano nel linguaggio XML e nel formato del markup.

Elementi oggetto di XAML

In genere, un elemento oggetto dichiara un'istanza di un tipo. Il tipo è definito negli assembly che forniscono i tipi di supporto per una tecnologia che utilizza XAML come linguaggio.

La sintassi degli elementi oggetto inizia sempre con una parentesi angolare di apertura (<), seguita dal nome del tipo in cui si desidera creare un'istanza. Il nome può includere un prefisso. Questo concetto verrà illustrato in seguito. Se lo si desidera, è quindi possibile dichiarare attributi nell'elemento oggetto. Per completare il tag dell'elemento oggetto, terminare con una parentesi angolare di chiusura (>). In alternativa, è possibile utilizzare una forma di chiusura automatica senza contenuto, completando il tag con una barra e una parentesi angolare di chiusura in successione (/>). Osservare nuovamente il frammento di markup illustrato in precedenza:

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

Vengono specificati due elementi oggetto: <StackPanel> (con contenuto e un tag di chiusura successivo) e <Button .../> (forma di chiusura automatica, con diversi attributi). Gli elementi oggetto StackPanel e Button vengono mappati ciascuno al nome di una classe definita da WPF e che fa parte degli assembly WPF. Quando si specifica il tag di un elemento oggetto, si crea un'istruzione per la creazione di una nuova istanza da parte dell'elaborazione XAML. Ogni istanza viene creata chiamando il costruttore predefinito del tipo sottostante durante l'analisi e il caricamento del markup XAML.

Sintassi per attributi (proprietà)

Spesso le proprietà di un oggetto possono essere espresse come attributi dell'elemento oggetto. Una sintassi per attributi definisce un nome per la proprietà impostata nella sintassi, seguito dall'operatore di assegnazione (=). Il valore di un attributo viene sempre specificato come stringa inclusa tra virgolette.

La sintassi per attributi è la sintassi per l'impostazione di proprietà più semplice, nonché la più intuitiva per gli sviluppatori che hanno già 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 gli elementi proprietà

Per alcune proprietà di un elemento oggetto, la sintassi per attributi non può essere utilizzata in quanto non è possibile esprimere l'oggetto o le informazioni necessarie per fornire il valore di proprietà in modo adeguato tra virgolette e nel rispetto delle limitazioni della stringa della sintassi di attributo. In questi casi, è possibile utilizzare una sintassi diversa, nota come sintassi per elementi proprietà,

La sintassi per il tag di inizio dell'elemento proprietà è <nomeTipo.nomeProprietà>. Il contenuto di tale tag è in genere un elemento oggetto del tipo accettato come valore dalla proprietà. Dopo avere specificato il contenuto, è necessario chiudere l'elemento proprietà con un tag di fine. La sintassi per il tag di fine è </nomeTipo.nomeProprietà>.

Se supportata, la sintassi per attributi è in genere più efficace e consente un markup più compatto. Si tratta tuttavia di una questione di stile e non di un limite tecnico. 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>

Sintassi per insiemi

Il linguaggio XAML include alcune ottimizzazioni che producono un markup più leggibile per l'utente. Una di queste ottimizzazioni prevede che se una proprietà specifica accetta un tipo di insieme, gli elementi dichiarati nel markup come elementi figlio in quel valore della proprietà diventano di conseguenza parte dell'insieme. In questo caso, un insieme di elementi oggetto figlio corrisponde al valore impostato nella proprietà dell'insieme.

Nell'esempio seguente viene illustrata la sintassi per insiemi per l'impostazione dei valori della proprietà GradientStops:

<LinearGradientBrush>
  <LinearGradientBrush.GradientStops>
    <!-- no explicit new GradientStopCollection, parser knows how to find or create -->
    <GradientStop Offset="0.0" Color="Red" />
    <GradientStop Offset="1.0" Color="Blue" />
  </LinearGradientBrush.GradientStops>
</LinearGradientBrush>

Proprietà di contenuto XAML

XAML specifica una funzionalità del linguaggio tramite cui una classe può designare esattamente una delle relative proprietà come proprietà di contenuto XAML. Gli elementi figlio dell'elemento oggetto vengono utilizzati per impostare il valore di questa proprietà di contenuto. In altre parole, solo per la proprietà di contenuto, è possibile omettere un elemento proprietà quando si imposta tale proprietà nel markup XAML ed è possibile produrre una metafora padre/figlio più visibile nel markup.

Ad esempio, Border specifica una proprietà di contenuto di Child. I due elementi Border seguenti vengono gestiti in modo identico. Il primo sfrutta la sintassi della proprietà di contenuto e omette l'elemento proprietà Border.Child. Il secondo specifica Border.Child in modo esplicito.

<Border>
  <TextBox Width="300"/>
</Border>
<!--explicit equivalent-->
<Border>
  <Border.Child>
    <TextBox Width="300"/>
  </Border.Child>
</Border>

Secondo le regole del linguaggio XAML, il valore di una proprietà di contenuto XAML deve essere specificato completamente prima o completamente dopo qualsiasi altro elemento proprietà nell'elemento oggetto. Ad esempio, il markup seguente non viene compilato:

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

Per ulteriori informazioni su questa restrizione nelle proprietà di contenuto XAML, vedere la sezione "Proprietà di contenuto XAML" di Descrizione dettagliata della sintassi XAML.

Contenuto di testo

Un numero ridotto di elementi XAML può elaborare il testo direttamente come contenuto. A tale scopo, deve verificarsi uno dei casi seguenti:

  • La classe deve dichiarare una proprietà di contenuto e tale proprietà di contenuto deve essere di un tipo assegnabile a una stringa (il tipo può essere Object). Qualsiasi oggetto ContentControl, ad esempio, utilizza Content come proprietà di contenuto ed è di tipo Object, che supporta il seguente utilizzo in un oggetto ContentControl pratico, ad esempio Button: <Button>Hello</Button>.

  • Il tipo deve dichiarare un convertitore di tipi e, in tal caso, il contenuto di testo viene utilizzato come testo di inizializzazione per il convertitore di tipi. Ad esempio, <Brush>Blue</Brush>. Nella pratica questo caso è meno comune.

  • Il tipo deve essere un tipo primitivo noto del linguaggio XAML.

Combinazione di proprietà di contenuto e sintassi per insiemi

Si consideri l'esempio seguente:

<StackPanel>
  <Button>First Button</Button>
  <Button>Second Button</Button>
</StackPanel>

Nell'esempio ogni elemento 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 proprietà di contenuto XAML.

  • Elemento oggetto UIElementCollection omesso: la proprietà Panel.Children accetta il tipo UIElementCollection, che implementa IList. In base alle regole XAML per l'elaborazione di insiemi come IList, è possibile omettere il tag dell'elemento dell'insieme. In questo caso, non è effettivamente possibile creare un'istanza di UIElementCollection, in quanto non espone un costruttore predefinito e per questo motivo l'elemento oggetto UIElementCollection risulta impostato come commento.

<StackPanel>
  <StackPanel.Children>
    <!--<UIElementCollection>-->
    <Button>First Button</Button>
    <Button>Second Button</Button>
    <!--</UIElementCollection>-->
  </StackPanel.Children>
</StackPanel>

Sintassi per attributi (eventi)

È possibile utilizzare la sintassi per attributi anche per membri che sono eventi anziché proprietà. In questo caso il nome dell'attributo corrisponde al nome dell'evento. Nell'implementazione WPF di eventi per XAML, il valore dell'attributo corrisponde al nome di un gestore che implementa il delegato dell'evento. Nel markup seguente, ad esempio, viene assegnato un gestore per l'evento Click a un controllo Button creato nel markup:

<Page 
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="ExampleNamespace.ExamplePage">
  <Button Click="Button_Click" >Click Me!</Button>
</Page>

La correlazione tra eventi e XAML in WPF è molto più complessa di questo semplice esempio di sintassi per attributi. Ci si potrebbe chiedere ad esempio, cosa rappresenti ClickHandler a cui viene fatto riferimento e come questo venga definito. Questi aspetti verranno illustrati nella sezione Eventi e code-behind XAML più avanti in questo argomento.

Maiuscolo e minuscolo e spazi vuoti in XAML

In genere, XAML effettua la distinzione tra maiuscole e minuscole. Per la risoluzione di tipi di supporto, XAML WPF effettua la distinzione tra maiuscole e minuscole in base alle stesse regole applicate da CLR relativamente a tale distinzione. 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. La distinzione tra maiuscole e minuscole viene effettuata anche per le parole chiave e le primitive del linguaggio XLAM. Per i valori la distinzione tra maiuscole e minuscole non viene sempre effettuata. 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 in Boolean dei tipi nativi del parser XAML WPF per la stringa consente già tali valori come equivalenti.

I processori e i serializzatori XAML WPF ignoreranno o rimuoveranno tutti gli spazi vuoti non significativi e normalizzeranno gli spazi vuoti significativi. Ciò è coerente con i requisiti di comportamento degli spazi vuoti predefiniti della specifica XAML. Questo comportamento è generalmente significativo solo quando si specificano stringhe all'interno di proprietà di contenuto XAML. In termini più semplici, in XAML i caratteri di spazio, avanzamento riga e tabulazione vengono convertiti in spazi e viene conservato solo l'eventuale spazio rilevato a una delle estremità di una stringa contigua. La spiegazione completa della gestione degli spazi vuoti in XAML non è oggetto di trattazione in questo argomento. Per informazioni dettagliate, vedere Elaborazione degli spazi vuoti in XAML.

Estensioni di markup

Le estensioni di markup sono un concetto del linguaggio XAML. Se utilizzate per specificare il valore di una sintassi per attributi, le parentesi graffe ({ e }) indicano l'utilizzo di un'estensione di markup. Questo utilizzo indica all'elaborazione XAML che, diversamente dal solito, i valori degli attributi non devono essere considerati valori di stringa letterale o valori convertibili in stringa.

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 per attributi per specificare valori per le proprietà anche quando le proprietà non supportano in generale una sintassi per attributi. Spesso, le estensioni di markup vengono utilizzate con tipi di espressione intermedi per abilitare funzionalità quali il posticipo di valori o il riferimento ad altri oggetti presenti solo in fase di esecuzione.

Nel markup seguente, ad esempio, viene impostato il valore della proprietà Style utilizzando la sintassi per attributi. La proprietà Style accetta un'istanza della classe Style, di cui per impostazione predefinita non è stato possibile creare un'istanza tramite 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>

Per un elenco di riferimento di tutte le estensioni di markup per il linguaggio XAML implementato specificamente in WPF, vedere Estensioni XAML WPF. Per un elenco di riferimento delle estensioni di markup definite da System.Xaml e più ampiamente disponibili per implementazioni XAML .NET Framework, vedere Funzionalità del linguaggio dello spazio dei nomi XAML (x:). Per ulteriori informazioni sui concetti correlati alle estensioni di markup, vedere Estensioni di markup e XAML WPF.

Convertitori di tipi

Nella sezione Sintassi per attributi è stato affermato che il valore dell'attributo deve poter essere impostato tramite una stringa. La gestione nativa di base della conversione delle stringhe in altri tipi di oggetto o valori primitivi si basa sul tipo String stesso, nonché su un'elaborazione nativa per determinati tipi, ad esempio DateTime o Uri. Molti tipi WPF o membri di tali tipi, tuttavia, estendono il comportamento di elaborazione degli attributi stringa di base in modo che le istanze di tipi di oggetto più complessi possano essere specificate come stringhe e attributi.

La struttura Thickness è un esempio di un tipo associato a una conversione di tipi abilitata per gli utilizzi di XAML. Thickness indica misure all'interno di un rettangolo annidato e viene utilizzata come valore per proprietà quali Margin. Inserendo un convertitore di tipi in Thickness, tutte le proprietà che utilizzano una struttura Thickness risultano più facili da specificare in XAML, in quanto possono essere specificate come attributi. Nell'esempio seguente vengono utilizzate una conversione di tipi e la sintassi per attributi per specificare un valore per una proprietà 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. Le 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>
NotaNota

Esiste inoltre un numero limitato di oggetti in cui la conversione dei tipi rappresenta l'unico modo pubblico per impostare una proprietà su quel tipo senza coinvolgere una sottoclasse, poiché il tipo stesso non dispone di un costruttore predefinito.Cursor è un esempio.

Per ulteriori informazioni sul supporto della conversione dei tipi e del relativo utilizzo per la sintassi per attributi, vedere TypeConverter e XAML.

Elementi radice XAML e spazi dei nomi XAML

Per essere sia un file XML ben formato sia un file XAML valido, un file XAML deve includere solo un elemento radice. Per scenari WPF tipici, è possibile utilizzare un elemento radice dotato di un significato prominente nel modello applicativo WPF, ad esempio Window o Page per una pagina, ResourceDictionary per un dizionario esterno oppure Application per la definizione dell'applicazione. Nell'esempio seguente viene illustrato l'elemento radice di un tipico file XAML per una pagina WPF, con l'elemento radice di 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 gli spazi dei nomi XAML che contengono le definizioni dei tipi per i tipi di supporto a cui il markup farà riferimento come elementi. L'attributo xmlns indica in modo specifico lo spazio dei nomi XAML predefinito. All'interno dello spazio dei nomi XAML predefinito gli elementi oggetto nel markup possono essere specificati senza prefisso. Per la maggior parte degli scenari con applicazioni WPF e per quasi tutti gli esempi forniti nelle sezioni di WPF nell'SDK, lo spazio dei nomi XAML predefinito viene mappato allo spazio dei nomi WPF https://schemas.microsoft.com/winfx/2006/xaml/presentation. L'attributo xmlns:x indica uno spazio dei nomi XAML aggiuntivo, che viene mappato allo spazio dei nomi del linguaggio XAML https://schemas.microsoft.com/winfx/2006/xaml.

Tale utilizzo di xmlns per definire un ambito per l'utilizzo e il mapping di un NameScope è coerente con la specifica XML 1.0. I NameScope XAML sono diversi dai NameScope XML solo in quanto nei primi vengono indicati anche alcuni aspetti correlati al supporto degli elementi del NameScope da parte dei tipi riguardo a risoluzione dei tipi e analisi di XAML.

Si noti che gli attributi xmlns sono strettamente necessari solo per l'elemento radice di ogni file XAML. Le definizioni xmlns si applicheranno a tutti gli elementi discendenti dell'elemento radice, un comportamento coerente con la specifica XML 1.0 per xmlns. Gli attributi xmlns sono inoltre consentiti in altri elementi sottostanti la radice e si applicherebbero a qualsiasi elemento discendente dell'elemento di definizione. Tuttavia, la definizione o ridefinizione frequente degli spazi dei nomi XAML può provocare uno stile di markup XAML di difficile lettura.

L'implementazione WPF del relativo processore XAML include un'infrastruttura che rileva gli assembly principali WPF. Gli assembly principali WPF contengono notoriamente i tipi che supportano i mapping WPF allo spazio dei nomi XAML predefinito. Ciò è consentito tramite la configurazione inclusa nel file di compilazione del progetto e nei sistemi di compilazione e del progetto WPF. La dichiarazione dello spazio dei nomi XAML predefinito come xmlns predefinito, pertanto, è l'unica operazione necessaria per fare riferimento a elementi XAML provenienti da assembly WPF.

Prefisso x:

Nell'esempio di elemento radice precedente è stato utilizzato il prefisso x: per eseguire il mapping dello spazio dei nomi XAML https://schemas.microsoft.com/winfx/2006/xaml, che è lo spazio dei nomi XAML dedicato che supporta costrutti di linguaggio XAML. Il prefisso x: viene utilizzato per il mapping di questo spazio dei nomi XAML nei modelli per i progetti, negli esempi e nella documentazione in tutto l'SDK. Lo spazio dei nomi XAML per il linguaggio XAML contiene diversi costrutti di programmazione che verranno utilizzati molto frequentemente in XAML. Di seguito viene fornito un elenco dei più comuni costrutti di programmazione del prefisso x: che verranno utilizzati:

  • x:Key: imposta una chiave univoca per ogni risorsa in un oggetto ResourceDictionary o concetti di dizionario simili di altri framework. x:Key sarà coinvolto probabilmente nel 90% degli utilizzi di x: osservati nel markup di un'applicazione WPF tipica.

  • x:Class: specifica lo spazio dei nomi CLR e il nome della classe che fornisce il code-behind per una pagina XAML. È necessario che tale classe supporti il code-behind per ciascun modello di programmazione WPF 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. In genere, si utilizzerà spesso una proprietà equivalente definita in WPF per x:Name. Tali proprietà eseguono specificamente il mapping a una proprietà di supporto CLR e risultano pertanto più utili per la programmazione di applicazioni, in cui spesso viene utilizzato codice di runtime per individuare gli elementi denominati da XAML inizializzato. Tra queste proprietà la più comune è FrameworkElement.Name. È ancora possibile utilizzare x:Name nei casi in cui la proprietà Name equivalente a livello di framework WPF non sia supportata in un tipo particolare. Tale situazione si verifica in determinati scenari di animazione.

  • x:Static: abilita il riferimento che restituisce un valore statico che non costituisce in altro modo 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 spesso la proprietà disponga di una conversione nativa da stringa a Type che rende facoltativo l'utilizzo dell'estensione di markup x:Type.

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

Prefissi personalizzati e tipi personalizzati in XAML

Per gli assembly personalizzati o per gli assembly esterni agli elementi principali WPF di PresentationCore, PresentationFramework e WindowsBase, è possibile specificare l'assembly come parte di un mapping xmlns personalizzato. È quindi possibile fare riferimento ai tipi dell'assembly in XAML, purché tale tipo sia stato implementato correttamente per supportare gli utilizzi di XAML desiderati.

Di seguito viene fornito un esempio molto semplice del funzionamento dei prefissi personalizzati nel markup XAML. Il prefisso custom è definito nel tag dell'elemento radice e viene mappato a un assembly specifico compresso e disponibile con l'applicazione. Questo assembly contiene un tipo NumericUpDown implementato per supportare l'utilizzo generale di XAML, nonché l'utilizzo di un'ereditarietà delle classi che ne consenta l'inserimento in questo punto specifico in un modello di contenuto XAML WPF. Un'istanza di questo controllo NumericUpDown viene dichiarata come elemento oggetto, utilizzando il prefisso in modo tale che un parser XAML sia in grado di riconoscere lo spazio dei nomi XAML contenente il tipo e pertanto la posizione dell'assembly di supporto che contiene la definizione del tipo.

<Page
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:custom="clr-namespace:NumericUpDownCustomControl;assembly=CustomLibrary"
    >
  <StackPanel Name="LayoutRoot">
    <custom:NumericUpDown Name="numericCtrl1" Width="100" Height="60"/>
...
  </StackPanel>
</Page>

Per ulteriori informazioni sui tipi personalizzati in XAML, vedere Classi XAML e personalizzate per WPF.

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 per XAML WPF.

Eventi e code-behind XAML

La maggior parte delle applicazioni WPF include sia markup che code-behind XAML. All'interno di un progetto, XAML viene scritto come file .xaml e per scrivere un file code-behind viene utilizzato un linguaggio CLR, ad esempio Microsoft Visual Basic o C#. Durante la compilazione dal markup di un file XAML come parte dei modelli di applicazione e di programmazione WPF, il percorso del file code-behind XAML per un file 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="ExampleNamespace.ExamplePage">
  <Button Click="Button_Click" >Click Me!</Button>
</Page>
Private Sub Button_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
    Dim b As Button = e.Source
    b.Foreground = Brushes.Red
End Sub
namespace ExampleNamespace
{
  public partial class ExamplePage
  {
    void Button_Click(object sender, RoutedEventArgs e)
    {
      Button b = e.Source as Button;
      b.Foreground = Brushes.Red;
    }
  }
}

Notare che il file code-behind utilizza lo spazio dei nomi CLR ExampleNamespace e dichiara ExamplePage come classe parziale all'interno di tale spazio dei nomi. Questo è parallelo al valore dell'attributo x:Class di ExampleNamespace.ExamplePage fornito nella radice del markup. Il compilatore del markup WPF creerà una classe parziale per ogni file XAML compilato 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 di code-behind in WPF, vedere la sezione di Code-behind e XAML in WPF relativa a code-behind, gestore eventi e requisiti delle classi parziali.

Se non si desidera creare un file code-behind distinto, è anche possibile incorporare il codice in un file XAML. Tuttavia, il codice inline è una tecnica meno versatile che presenta limitazioni sostanziali. Per informazioni dettagliate, vedere Code-behind e XAML in WPF.

Eventi indirizzati

Un evento indirizzato è una particolare funzionalità evento fondamentale per WPF. Gli eventi indirizzati consentono a un elemento di gestire un evento generato da un elemento diverso, purché gli elementi siano connessi tramite una relazione di struttura ad albero. Quando si specifica la gestione dell'evento con un attributo XAML, l'evento indirizzato può essere ascoltato e gestito in qualsiasi elemento, inclusi quelli che non elencano l'evento specifico 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 sul funzionamento degli eventi indirizzati, vedere Cenni preliminari sugli eventi indirizzati.

Elementi denominati XALM

Per impostazione predefinita, l'istanza di oggetto creata in un oggetto grafico mediante l'elaborazione di un elemento oggetto XAML non possiede un identificatore univoco o un riferimento a un oggetto. Al contrario, 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 nel codice in un secondo momento. Per fornire accesso standard agli oggetti creati tramite una definizione del markup, in XAML viene definito 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 a tale istanza) e il code-behind può fare riferimento agli elementi denominati per gestire le interazioni di runtime all'interno dell'applicazione. Questa connessione tra istanze e variabili viene effettuata tramite il compilatore di markup XAML WPF e più specificatamente coinvolge funzionalità e modelli non approfonditi in questo argomento, ad esempio InitializeComponent.

Gli elementi XAML a livello di framework WPF ereditano una proprietà Name, che equivale all'attributo x:Name definito in XAML. Altre classi forniscono equivalenti a livello di proprietà per x:Name, che in genere viene definito anche come proprietà Name. In generale se non è possibile individuare una proprietà Name nella tabella dei membri dell'elemento o del tipo scelto, utilizzare x:Name in alternativa. I valori x:Name forniranno a un elemento XAML un identificatore che può essere utilizzato in fase di esecuzione dai sottosistemi specifici o dai metodi di utilità, ad esempio FindName.

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>
 Private Sub RemoveThis(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
     Dim fe As FrameworkElement = e.Source
     If (buttonContainer.Children.Contains(fe)) Then
         buttonContainer.Children.Remove(fe)
     End If
End Sub
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 XAML 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 denota un NameScope XAML univoco, il cui limite è costituito dall'elemento radice della pagina. Altre origini di markup, tuttavia, 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 XAML propri non necessariamente connessi al NameScope XAML della pagina. Per ulteriori informazioni su x:Name e i NameScope XAML, vedere Name, Direttiva x:Name o NameScope XAML WPF.

Proprietà ed eventi associati

XAML specifica una funzionalità del linguaggio che consente di specificare determinati eventi o proprietà in qualsiasi elemento, indipendentemente dalla presenza della proprietà o dell'evento all'interno delle definizioni del tipo per l'elemento per cui è impostato l'evento o la proprietà. La versione delle proprietà di questa funzionalità è denominata proprietà associata, la versione degli eventi è denominata evento associato. Concettualmente, è possibile pensare alle proprietà associate e agli eventi associati come a membri globali che possono essere impostati in qualsiasi elemento o istanza di oggetto XAML. Tuttavia, tale elemento, classe o infrastruttura più ampia dovrà supportare un archivio delle proprietà di supporto per i valori associati.

Le proprietà associate in XAML vengono in genere utilizzate tramite la sintassi per attributi. Per specificare una proprietà associata in questa sintassi, è necessario utilizzare la forma 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 WPF la maggior parte o tutte le proprietà associate sono implementate anche come proprietà di dipendenza. Per informazioni dettagliate, vedere Cenni preliminari sulle proprietà associate.

Gli eventi associati utilizzano una forma 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 nell'elemento. Gli utilizzi di eventi associati in XAML WPF sono meno comuni. Per ulteriori informazioni, vedere Cenni preliminari sugli eventi associati.

Tipi di base e XAML

Il markup XAML WPF sottostante e il relativo spazio dei nomi XAML sono un insieme di tipi corrispondenti a oggetti CLR, nonché a elementi di markup da utilizzare in XAML. Tuttavia non è possibile eseguire il mapping di tutte le classi agli elementi. Classi astratte come ButtonBase e alcune classi di base non astratte vengono utilizzate per l'ereditarietà nel modello a oggetti CLR. Le classi di base, incluse quelle astratte, continuano a essere importanti per lo sviluppo di XAML, in quanto ciascuno degli elementi XAML concreti eredita i membri da una classe di base nella relativa gerarchia. Spesso tali membri includono proprietà che possono essere impostate come attributi nell'elemento oppure eventi che possono essere gestiti. FrameworkElement è la classe di base concreta dell'UI di WPF a livello di framework WPF. Durante la progettazione dell'UI, 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 APIs che eseguono il mirroring delle APIs in FrameworkElement. La combinazione di attributi a livello di elemento e di un modello a oggetti CLR fornisce un set di proprietà comuni che è possibile impostare nella maggior parte degli elementi XAML concreti, indipendentemente dall'elemento XAML specifico e dal relativo tipo sottostante.

Sicurezza XAML

XAML è un linguaggio di markup che rappresenta direttamente la creazione di istanze di oggetti e la relativa esecuzione. Gli elementi creati in XAML, pertanto, hanno la stessa capacità di interagire con risorse di sistema (quali accesso di rete e IO file system) del codice generato equivalente.

WPF supporta la Code Access Security (CAS) del framework di sicurezza .NET Framework 4. Di conseguenza, il contenuto WPF in esecuzione nell'area Internet dispone di autorizzazioni di esecuzione ridotte. " In questa area Internet vengono in genere eseguiti il codice "XAML separato", ovvero pagine di XAML non compilato interpretato in fase di caricamento da parte di un visualizzatore XAML, e l'XAML browser application (XBAP), che utilizzano lo stesso set di autorizzazioni. Il codice XAML caricato in un'applicazione completamente attendibile, tuttavia, dispone dello stesso accesso alle risorse di sistema dell'applicazione host. Per ulteriori informazioni, vedere Sicurezza con attendibilità parziale in WPF.

Caricamento di XAML dal codice

Sebbene sia possibile utilizzare XAML per definire un'interfaccia utente completa, è talvolta opportuno definire solo una parte dell'interfaccia utente tramite XAML. Questa funzionalità può risultare utile per consentire una personalizzazione parziale, l'archiviazione locale di informazioni, l'utilizzo di XAML per fornire un oggetto business o per molti altri scenari possibili. La chiave per questi scenari è la classe XamlReader e il relativo metodo Load. L'input è un file XAML, mentre l'output è un oggetto che rappresenta l'intera struttura ad albero di oggetti di runtime creata dal 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à appropriata nel modello di contenuto che dispone di funzionalità di visualizzazione e che notifica al motore di esecuzione che è stato aggiunto nuovo contenuto nell'applicazione, è possibile modificare in modo piuttosto semplice il contenuto di un'applicazione in esecuzione tramite il caricamento in XAML. Notare che questa funzionalità in genere è disponibile solo nelle applicazioni con attendibiiltà completa, a causa delle ovvie implicazioni di sicurezza del caricamento di file all'interno delle applicazioni in esecuzione.

Fasi successive

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

Nel caso in cui non sia ancora stato fatto, è possibile svolgere i passaggi dell'esercitazione Procedura dettagliata: introduzione a WPF. Durante la creazione dell'applicazione basata sul markup descritta nell'esercitazione, l'esercizio consentirà di approfondire molti dei concetti trattati 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 (WPF) vengono forniti maggiori dettagli su come compilare applicazioni che includono XAML utilizzando la riga di comando e Microsoft Visual Studio.

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

Vedere anche

Concetti

Descrizione dettagliata della sintassi XAML

Classi XAML e personalizzate per WPF

Cenni preliminari sugli elementi di base

Strutture ad albero in WPF

Altre risorse

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

Estensioni XAML WPF