XAML e classi personalizzate

Aggiornamento: novembre 2007

Extensible Application Markup Language (XAML) supporta la possibilità di definire una classe o una struttura personalizzata in qualsiasi linguaggio Common Language Runtime (CLR) e quindi di accedere a quella classe utilizzando il markup XAML, incluso mediante una combinazione di sintassi XAML definita da Windows Presentation Foundation (WPF) e di tag XAML della classe personalizzata all'interno dello stesso file di markup. In questo argomento vengono discussi i requisiti che una classe personalizzata deve soddisfare per poter essere utilizzata come elemento XAML.

Nel presente argomento sono contenute le seguenti sezioni.

  • Classi personalizzate in applicazioni o assembly
  • Requisiti per una classe personalizzata come elemento XAML
  • Requisiti per proprietà di una classe personalizzata come attributi XAML
  • Requisiti per la sintassi per attributi del gestore eventi XAML negli eventi di una classe personalizzata
  • Scrittura di proprietà di insieme
  • Dichiarazione delle proprietà di contenuto XAML
  • Serializzazione di XAML
  • Argomenti correlati

Classi personalizzate in applicazioni o assembly

Le classi personalizzate che sono utilizzate in XAML possono essere definite in due modi distinti: all'interno del code-behind o di un altro codice che genera l'applicazione Windows Presentation Foundation (WPF) primaria oppure come classe in un assembly separato, ad esempio un file eseguibile o una DLL utilizzata come libreria di classi. Ognuno di questi approcci presenta vantaggi e svantaggi particolari.

  • Il vantaggio della creazione di una libreria di classi consiste nella possibilità di condividere una qualsiasi di queste classi personalizzate tra un gran numero di applicazioni diverse. Una libreria separata inoltre rende più semplice la gestione dei problemi di controllo della versione delle applicazioni e semplifica la creazione di una classe che si intende utilizzare come elemento radice in una pagina XAML.

  • Il vantaggio della definizione di classi personalizzate nell'applicazione consiste nel fatto che si tratta di una tecnica relativamente semplice, che riduce al minimo i problemi di distribuzione e di test che si verificano quando si introducono assembly separati oltre al file eseguibile principale. Tuttavia, uno svantaggio rilevante è rappresentato dall'impossibilità di utilizzare classi definite nello stesso assembly dell'elemento radice di una pagina XAML.

  • Indipendentemente dal fatto che siano definite nello stesso assembly o in un assembly diverso, è necessario eseguire il mapping delle classi personalizzate tra spazio dei nomi CLR e spazio dei nomi XML per consentirne l'utilizzo in XAML come elementi. Vedere Spazi dei nomi XAML e mapping dello spazio dei nomi.

Requisiti per una classe personalizzata come elemento XAML

Affinché sia possibile crearne un'istanza come elemento oggetto, la classe deve soddisfare i seguenti requisiti:

  • La classe personalizzata deve essere pubblica e deve supportare un costruttore pubblico predefinito (senza parametri). Le strutture di codice gestito supportano implicitamente un costruttore di questo tipo.

  • La classe personalizzata non deve essere una classe nidificata (le classi nidificate e il "punto" nella relativa sintassi interferiscono con le altre funzionalità WPF, ad esempio le proprietà associate).

Oltre ad attivare la sintassi per elementi oggetto, viene attivata anche la sintassi per elementi proprietà per tutte le altre proprietà pubbliche che accettano quell'oggetto come tipo di valore. Ciò è dovuto al fatto che non è possibile creare un'istanza dell'oggetto come elemento oggetto e quindi inserire il valore di elemento proprietà di tale proprietà.

Strutture

È sempre possibile costruire in XAML le strutture definite come tipi personalizzati WPF. Questo avviene perché i compilatori CLR creano in modo implicito un costruttore predefinito per una struttura che inizializza tutti i valori delle proprietà alle impostazioni predefinite. In alcuni casi, il comportamento predefinito della costruzione e/o utilizzo dell'elemento oggetto per una struttura non è appropriato. Il motivo può essere che la struttura è prevista per inserire valori e funzioni concettualmente come unione i cui valori potrebbero disporre di interpretazioni che si escludono reciprocamente, pertanto nessuna delle proprietà è impostabile. Un esempio WPF di tale struttura è GridLength. Tali strutture devono generalmente implementare un convertitore di tipo, in modo che i valori possano essere espressi sotto forma di attributo, utilizzando convenzioni di stringa che creano le diverse interpretazioni o modalità dei valori della struttura e la struttura deve esporre un comportamento simile per la costruzione del codice tramite un costruttore non predefinito.

Requisiti per proprietà di una classe personalizzata come attributi XAML

Le proprietà devono fare riferimento a un tipo per valore (ad esempio una primitiva) oppure utilizzare una classe per il tipo che sia un costruttore predefinito o un convertitore di tipi dedicato a livello della classe.

In alternativa, la proprietà può fare riferimento a un tipo di classe astratta oppure a un'interfaccia. Per le classi astratte o le interfacce, l'aspettativa è che in fase di esecuzione il valore della proprietà sia compilato con istanze della classe pratica che implementano l'interfaccia oppure con istanze della classe che derivano dalla classe astratta.

Le proprietà possono essere dichiarate in una classe astratta, ma possono essere impostate solo su classi pratiche che derivano dalla classe astratta, in quanto la creazione dell'elemento oggetto per la classe richiede un costruttore predefinito pubblico per la classe.

Sintassi per attributi abilitata per il convertitore dei tipi

Se si fornisce un convertitore dei tipi dedicato con attribuiti a livello di classe, la conversione dei tipi applicata attiva la sintassi per attributi per qualsiasi proprietà per la quale è necessario creare un'istanza di quel tipo. Un convertitore dei tipi non consente l'utilizzo dell'elemento oggetto del tipo; solo la presenza di un costruttore predefinito per quel tipo consente l'utilizzo dell'elemento oggetto. Pertanto, le proprietà che sono attivate dal convertitore dei tipi in genere non possono essere utilizzate nella sintassi per proprietà, a meno che il tipo stesso non supporti anche la sintassi per elementi oggetto. L'eccezione è costituita dalla possibilità di specificare una sintassi per elementi proprietà, ma dalla necessità che l'elemento proprietà contenga una stringa. Tale utilizzo in realtà è essenzialmente equivalente all'utilizzo di una sintassi per attributi e non è comune a meno che non sia necessaria una gestione degli spazi vuoti più affidabile del valore dell'attributo. L'utilizzo dell'elemento proprietà riportato di seguito, ad esempio, accetta una stringa e l'equivalente dell'utilizzo dell'attributo:

<Button>Hallo!
  <Button.Language>
    de-DE
  </Button.Language>
</Button>
<Button Language="de-DE">Hallo!</Button>

Esempi di proprietà nelle quali è consentita la sintassi per attributi ma non è consentita la sintassi per elementi che contiene un elemento oggetto tramite XAML sono le diverse proprietà che accettano il tipo Cursor. La classe Cursor contiene un convertitore dei tipi dedicato CursorConverter, ma non espone un costruttore predefinito, pertanto la proprietà Cursor può essere impostata solo tramite la sintassi per attributi anche se il tipo Cursor effettivo è un tipo di riferimento.

Convertitori dei tipi per proprietà

In alternativa, la proprietà stessa può dichiarare un convertitore dei tipi a livello della proprietà. In tal modo viene attivato un "minilinguaggio" che crea un'istanza di oggetti del tipo della proprietà inline, elaborando i valori di stringa in ingresso dell'attributo come input per un'operazione ConvertFrom basata sul tipo appropriato. In genere, tale operazione viene eseguita per fornire una funzione di accesso pratica e non con lo scopo unico di consentire l'impostazione di una proprietà in XAML. Tuttavia, è anche possibile utilizzare convertitori dei tipi per gli attributi nei quali si desidera utilizzare tipi CLR esistenti che non forniscono un costruttore predefinito o un convertitore dei tipi con attributi. Esempi dalle API WPF sono determinate proprietà che accettano il tipo CultureInfo. In questo caso, WPF ha utilizzato il tipo Microsoft .NET FrameworkCultureInfo esistente per risolvere meglio i problemi degli scenari di compatibilità e migrazione utilizzati nelle versioni precedenti dei framework, ma il tipo CultureInfo non supportava i costruttori necessari o la conversione dei tipi a livello di tipo da utilizzare direttamente come valore di proprietà XAML.

Ogni volta che si espone una proprietà che presenta un utilizzo XAML, in particolare se si è un autore di controlli, è necessario considerare di supportare quella proprietà con una proprietà di dipendenza. Ciò è vero specialmente se si utilizza l'implementazione Windows Presentation Foundation (WPF) esistente del processore XAML, perché è possibile migliorare le prestazioni utilizzando il supporto DependencyProperty. Una proprietà di dipendenza esporrà funzionalità del sistema di proprietà per la proprietà che gli utenti prevedono come proprietà accessibile XAML. Tale proprietà include funzionalità quali l'animazione, l'associazione dati e il supporto degli stili. Per ulteriori informazioni, vedere Proprietà Dependency personalizzate e Caricamento XAML e proprietà di dipendenza.

Scrittura e associazione di attributi a un convertitore dei tipi

Spesso è necessario scrivere una classe derivata TypeConverter personalizzata per fornire la conversione dei tipi per il tipo della proprietà utilizzato. Per istruzioni sulle modalità di derivazione e di creazione di un convertitore dei tipi in grado di supportare gli utilizzi XAML e sulle modalità di applicazione di TypeConverterAttribute, vedere TypeConverter e XAML.

Requisiti per la sintassi per attributi del gestore eventi XAML negli eventi di una classe personalizzata

Per poter essere utilizzato come evento CLR, l'evento deve essere esposto come evento pubblico in una classe che supporta un costruttore predefinito oppure in una classe astratta in cui è possibile accedere all'evento nelle classi derivate. Per essere utilizzato in modo appropriato come evento indirizzato, l'evento CLR deve implementare i metodi espliciti add e remove, che aggiungono e rimuovono gestori per la firma dell'evento CLR e inoltrare quei gestori ai metodi AddHandler e RemoveHandler. Questi metodi aggiungono o rimuovono i gestori per l'archivio del gestore eventi indirizzati nell'istanza alla quale è associato l'evento.

Nota

È possibile registrare direttamente i gestori per gli eventi indirizzati utilizzando AddHandler e non definire intenzionalmente un evento CLR che espone l'evento indirizzato . Tale operazione non è consigliabile in genere, in quanto l'evento non attiverà la sintassi per attributi XAML per associare i gestori e la classe risultante offrirà una visualizzazione XAML meno trasparente del modello a oggetti della classe.

Scrittura di proprietà di insieme

Le proprietà che accettano un tipo di insieme presentano una sintassi XAML che consente di specificare gli oggetti che vengono aggiunti all'insieme. Questa sintassi presenta due funzionalità rilevanti.

  • L'oggetto che rappresenta l'oggetto insieme non deve essere specificato nella sintassi per elementi oggetto. La presenza di quel tipo di insieme è implicita ogni volta che in XAML si specifica una proprietà che accetta un tipo di insieme.

  • Gli elementi figlio della proprietà dell'insieme vengono elaborati per diventare membri dell'insieme. Di norma, l'accesso del codice ai membri di un insieme viene eseguito tramite metodi di insieme quali Add oppure mediante una proprietà dell'indicizzatore di insiemi. Tuttavia, la sintassi XAML non supporta metodi o indicizzatori. Dal momento che gli insiemi sono un requisito molto comune per la compilazione di una struttura ad albero di elementi, sono necessari alcuni modi per popolarli nella sintassi XAML dichiarativa. Pertanto, gli elementi figlio di una proprietà dell'insieme vengono elaborati aggiungendoli all'insieme che rappresenta il valore del tipo di proprietà dell'insieme.

Il processore XAML WPF utilizza la seguente definizione relativamente agli elementi che costituiscono una proprietà dell'insieme. Il tipo di proprietà della proprietà deve implementare uno dei seguenti elementi:

Ognuno di questi tipi dispone di un metodo Add, utilizzato dal processore XAML per aggiungere elementi all'insieme sottostante.

Nota

L'oggetto List generico e le interfacce Dictionary (IList<T> e IDictionary<TKey, TValue>) non sono supportati per il rilevamento dell'insieme da parte del processore WPF XAML. Tuttavia, è possibile utilizzare la classe List<T> come classe di base, poiché implementa direttamente IList oppure Dictionary<TKey, TValue> come classe di base, poiché implementa direttamente IDictionary.

Quando si dichiara una proprietà che accetta un insieme, prestare attenzione alle modalità con cui quel valore di proprietà viene inizializzato nelle nuove istanze del tipo. Se non si sta implementando la proprietà come proprietà di dipendenza, è opportuno fare in modo che la proprietà utilizzi un campo di backup che chiama il costruttore del tipo di insieme. Se la proprietà è una proprietà di dipendenza, potrebbe essere necessario inizializzare proprietà dell'insieme come parte del costruttore del tipo predefinito. Ciò si verifica in quanto una proprietà di dipendenza accetta il relativo valore predefinito dai metadati e in genere non si desidera che il valore iniziale di una proprietà dell'insieme sia un insieme statico, condiviso (è necessario che esista un'istanza di insieme per ogni istanza del tipo contenitore). Per ulteriori informazioni, vedere Proprietà Dependency personalizzate.

È possibile implementare un tipo di insieme personalizzato per la proprietà dell'insieme. A causa del trattamento della proprietà dell'insieme implicito, il tipo di insieme personalizzato non deve necessariamente fornire un costruttore predefinito per essere utilizzata implicitamente in XAML. Tuttavia, se si desidera, è possibile fornire un costruttore predefinito per il tipo di insieme. Tale operazione può essere utile, in quanto se non si fornisce un costruttore predefinito, non è possibile dichiarare in modo esplicito l'insieme come elemento oggetto. È possibile che alcuni autori di markup preferiscano considerare l'insieme esplicito una questione di stile del markup. Inoltre, un costruttore predefinito può semplificare i requisiti dell'inizializzazione quando si creano nuovi oggetti che utilizzano il tipo di insieme come valore della proprietà.

Dichiarazione delle proprietà di contenuto XAML

Il linguaggio XAML definisce il concetto di una proprietà di contenuto XAML. Ogni classe che è possibile utilizzare nella sintassi per oggetti può disporre esattamente una proprietà di contenuto XAML. Per dichiarare una proprietà in modo che sia la proprietà di contenuto XAML per la classe, applicare l'oggetto ContentPropertyAttribute come parte della definizione della classe. Specificare il nome della proprietà di contenuto XAML desiderata come Name nell'attributo.

È possibile specificare una proprietà dell'insieme in modo che sia la proprietà di contenuto XAML. Tale operazione genera un utilizzo di quella proprietà in base al quale l'elemento oggetto può disporre di uno o più elementi figlio senza che si frappongano elementi oggetto di insieme o tag di elementi proprietà. Tali elementi vengono quindi trattati come valore per la proprietà di contenuto XAML e aggiunti all'istanza dell'insieme di supporto.

Alcune proprietà di contenuto XAML WPF esistenti utilizzano il tipo di proprietà di Object. Ciò attiva una proprietà di contenuto XAML che è in grado di accettare valori primitivi quali un oggetto String nonché di accettare un valore di oggetto con riferimento singolo. Se si segue questo modello, il tipo utilizzato è responsabile della determinazione del tipo oltre che della gestione dei tipi possibili. La ragione più comune per un modello di tipo Object è quella di supportare sia un'aggiunta semplice di contenuto oggetto come stringa (che riceve un trattamento di presentazione predefinito), sia un'aggiunta di contenuto oggetto avanzata, che specifica una presentazione non predefinita.

Serializzazione di XAML

Per determinati scenari, ad esempio se si è un autore di controlli, è inoltre possibile che si desideri assicurare che qualsiasi rappresentazione dell'oggetto per il quale è possibile creare un'istanza in XAML possa essere serializzata nuovamente nell'XAML equivalente. I requisiti della serializzazione non sono descritti in questo argomento. Vedere le proprietà Cenni preliminari sulla modifica di controlli e Struttura ad albero e serializzazione degli elementi.

Vedere anche

Concetti

Cenni preliminari su XAML

Proprietà Dependency personalizzate

Cenni preliminari sulla modifica di controlli

Cenni preliminari sugli elementi di base

Caricamento XAML e proprietà di dipendenza