Condividi tramite


Panoramica delle estensioni di markup per XAML

Le estensioni di markup sono una tecnica XAML per ottenere un valore che non è una primitiva né un tipo XAML specifico. Per utilizzo dell'attributo, le estensioni di markup utilizzano la sequenza di caratteri nota costituita da una parentesi graffa aperta { per l'immissione dell'ambito dell'estensione di markup e da una parentesi graffa chiusa }. Quando si utilizzano i servizi XAML di .NET Framework, è possibile utilizzare alcune delle estensioni di markup predefinite del linguaggio XAML contenute nell'assembly System.Xaml. È inoltre possibile creare una sottoclasse dalla classe MarkupExtension, definita in System.Xaml, e definire estensioni di markup personalizzate. In alternativa, è possibile utilizzare le estensioni di markup definite da un particolare framework se già si fa riferimento a tale framework.

Quando viene eseguito l'accesso a un utilizzo dell'estensione di markup, il writer di oggetti XAML può fornire servizi a una classe MarkupExtension personalizzata tramite un punto di connessione del servizio nell'override del metodo MarkupExtension.ProvideValue. I servizi possono essere utilizzati per ottenere il contesto relativo all'utilizzo, funzionalità specifiche del writer di oggetti, il contesto dello schema XAML e così via.

Nel presente argomento sono contenute le seguenti sezioni.

  • Estensioni di markup definite da XAML
  • Classe base di MarkupExtension
  • Definizione del tipo di supporto per un'estensione di markup personalizzata
  • Modelli di costruttore e argomenti posizionali per un'estensione di markup personalizzata
  • Argomenti denominati per un'estensione di markup personalizzata
  • Accesso al contesto del provider di servizi da un'implementazione dell'estensione di markup
  • Utilizzo dell'elemento proprietà di un'estensione di markup
  • Associazione di attributi per un'estensione di markup personalizzata
  • Serializzazione degli utilizzi di estensioni di markup
  • Estensioni di markup nel flusso del nodo XAML
  • Argomenti correlati

Estensioni di markup definite da XAML

Diverse estensioni di markup vengono implementate dai servizi XAML di .NET Framework per il supporto del linguaggio XAML. Le estensioni di markup corrispondono a parti della specifica di XAML come linguaggio. In genere, queste estensioni sono identificabili dal prefisso x: nella sintassi come illustrato nell'utilizzo comune. Le implementazioni dei servizi XAML di .NET Framework per questi elementi del linguaggio XAML derivano tutte dalla classe di base MarkupExtension.

NotaNota

Il prefisso x: viene utilizzato per il mapping dello spazio dei nomi XAML tipico dello spazio dei nomi del linguaggio XAML, nell'elemento radice di una produzione XAML.Ad esempio, nei modelli di progetto e pagina di Visual Studio per diversi framework specifici, avviare un file XAML utilizzando il mapping x:.Nel mapping dello spazio dei nomi XAML personalizzato è possibile scegliere un token di prefisso diverso. Tuttavia, per identificare le entità che rappresentano una parte definita dello spazio dei nomi XAML del linguaggio XAML, in questa documentazione viene utilizzato il mapping x: predefinito anziché lo spazio dei nomi XAML predefinito di un framework specifico o altri spazi dei nomi CLR o XML arbitrari.

x:Type

x:Type fornisce l'oggetto Type per il tipo denominato. Questa funzionalità viene il più delle volte utilizzata nei meccanismi di rinvio che utilizzano il tipo CLR sottostante e la derivazione del tipo come moniker o identificatore di raggruppamento. Gli stili e i modelli WPF, nonché il loro utilizzo delle proprietà TargetType, sono un esempio specifico. Per ulteriori informazioni, vedere Estensione del markup x:Type.

x:Static

x:Static produce valori statici da entità di codice di tipo di valore che non sono direttamente il tipo del valore di una proprietà, ma possono essere valutate in base a tale tipo. Ciò è utile per specificare valori già esistenti come costanti note in una definizione del tipo. Per ulteriori informazioni, vedere Estensione del markup x:Static.

x:Null

x:Null specifica null come valore per un membro XAML. In base alla progettazione di tipi specifici o a concetti di framework più ampi, non sempre null è un valore predefinito di una proprietà o il valore implicito dell'attributo di una stringa vuota. Per ulteriori informazioni, vedere Estensione del markup x:Null.

x:Array

x:Array supporta la creazione di matrici generali nella sintassi XAML, in casi in cui si sceglie intenzionalmente di non utilizzare il supporto degli insiemi fornito dagli elementi di base e dai modelli di controllo. Per ulteriori informazioni, vedere Estensione del markup x:Array. Nel caso specifico di XAML 2009, l'accesso alle matrici avviene come primitive di linguaggio anziché come un'estensione. Per ulteriori informazioni, vedere Funzionalità del linguaggio XAML 2009.

x:Reference

x:Reference fa parte di XAML 2009, un'estensione del set del linguaggio originale (2006). x:Reference rappresenta un riferimento a un altro oggetto esistente in un oggetto grafico. Tale oggetto viene definito dal relativo attributo x:Name. Per ulteriori informazioni, vedere estensione di markup x:Reference.

Altri costrutti x:

Esistono altri costrutti x: che supportano le funzionalità del linguaggio XAML, che non sono tuttavia implementati come estensioni di markup. Per ulteriori informazioni, vedere Funzionalità del linguaggio dello spazio dei nomi XAML (x:).

Classe base di MarkupExtension

Per definire un'estensione di markup personalizzata che possa interagire con le implementazioni predefinite di reader XAML e writer XAML in System.Xaml, è possibile derivare una classe dalla classe MarkupExtension astratta. Tale classe dispone di un unico metodo di cui eseguire l'override, ovvero ProvideValue. Potrebbe inoltre essere necessario definire costruttori aggiuntivi per il supporto di argomenti dell'utilizzo dell'estensione di markup, nonché le proprietà impostabili corrispondenti.

Tramite ProvideValue, un'estensione di markup personalizzata dispone di accesso a un contesto del servizio che segnala l'ambiente in cui l'estensione di markup viene in effetti richiamata da un processore XAML. Nel percorso di caricamento si tratta in genere di un oggetto XamlObjectWriter. Nel percorso di salvataggio si tratta in genere di un oggetto XamlXmlWriter. Il contesto del servizio viene segnalato come classe di contesto del provider di servizi XAML interna che implementa un modello del provider di servizi. Per ulteriori informazioni sui servizi disponibili e su ciò che rappresentano, vedere Convertitori di tipi ed estensioni di markup per XAML.

La classe dell'estensione di markup deve utilizzare un livello di accesso pubblico. I processori XAML devono essere sempre in grado di creare un'istanza della classe di supporto dell'estensione di markup in modo da utilizzare i relativi servizi.

Definizione del tipo di supporto per un'estensione di markup personalizzata

Quando si utilizzano i servizi XAML di .NET Framework o framework basati sui servizi XAML di .NET Framework, esistono due possibilità per denominare il tipo di supporto dell'estensione di markup. Il nome del tipo è rilevante per la modalità con cui i writer dell'oggetto XAML tentano di accedere e richiamare un tipo di supporto dell'estensione di markup quando rilevano un utilizzo dell'estensione di markup in XAML. Utilizzare una delle strategie di denominazione seguenti:

  • Denominare il tipo in modo che corrisponda esattamente al token di utilizzo del markup XAML. Ad esempio, per supportare l'utilizzo di un'estensione {Collate ...}, denominare il tipo di supporto Collate.

  • Denominare il tipo in modo che corrisponda al token della stringa dell'utilizzo seguito dal suffisso Extension. Ad esempio, per supportare l'utilizzo di un'estensione {Collate ...}, denominare il tipo di supporto CollateExtension.

L'ordine di ricerca prevede che venga cercato per primo il nome della classe con il suffisso Extension, quindi il nome della classe senza il suffisso Extension.

Dal punto di vista dell'utilizzo del markup, l'inclusione del suffisso Extension come parte dell'utilizzo è una procedura valida. Tuttavia, Extension viene considerato a tutti gli effetti parte del nome della classe, per cui i writer di oggetti XAML non riuscirebbero a risolvere una classe di supporto dell'estensione di markup per quell'utilizzo se la stessa classe non avesse il suffisso Extension.

Costruttore predefinito

Per tutti i tipi di supporto delle estensioni di markup, è necessario esporre un costruttore predefinito pubblico. È necessario un costruttore predefinito per qualsiasi caso in cui un writer dell'oggetto XAML crei un'istanza dell'estensione di markup dall'utilizzo di un elemento oggetto. L'utilizzo dell'elemento oggetto di supporto è un'aspettativa legittima per un'estensione di markup, specialmente per la serializzazione. È tuttavia possibile implementare un'estensione di markup senza un costruttore pubblico quando si intende supportare solo gli utilizzi degli attributi dell'estensione di markup.

Se l'utilizzo dell'estensione di markup non dispone di argomenti, il costruttore predefinito sarà necessario per supportare l'utilizzo.

Modelli di costruttore e argomenti posizionali per un'estensione di markup personalizzata

Per un'estensione di markup con utilizzo degli argomenti previsto, i costruttori pubblici devono corrispondere alle modalità dell'utilizzo previsto. In altri termini, se l'estensione di markup viene progettata per richiedere un argomento posizionale come utilizzo valido, è necessario supportare un costruttore pubblico con un parametro di input che accetti l'argomento posizionale.

Si supponga ad esempio che sia previsto che l'estensione di markup Collate supporti solo una modalità in cui è presente un argomento posizionale che rappresenta la relativa modalità, specificato come costante di enumerazione CollationMode. In questo caso, è necessario che sia presente un costruttore nel formato seguente:

public Collate(CollationMode collationMode) {...}

A un livello di base, gli argomenti passati a un'estensione di markup sono costituiti da una stringa in quanto vengono inoltrati dai valori dell'attributo del markup. È possibile rendere stringhe tutti gli argomenti e utilizzare l'input a tale livello. Si dispone tuttavia dell'accesso a determinate attività di elaborazione che vengono eseguite prima del passaggio degli argomenti dell'estensione di markup alla classe di supporto.

L'elaborazione viene eseguita a livello concettuale come se l'estensione di markup fosse un oggetto da creare, quindi vengono impostati i valori di membro. Ogni proprietà specificata da impostare viene valutata nello stesso modo in cui un membro specificato può essere impostato su un oggetto creato durante l'analisi del codice XAML. Vi sono due differenze importanti:

  • Come osservato in precedenza, non è necessario che un'estensione di markup disponga di un costruttore predefinito affinché sia possibile crearne un'istanza in XAML. La relativa costruzione di oggetti viene rinviata fino a quando gli argomenti possibili corrispondenti nella sintassi del testo non vengono suddivisi in token e valutati come argomenti posizionali o denominati e il costruttore appropriato non viene a quel punto chiamato.

  • È possibile annidare gli utilizzi delle estensioni di markup. L'estensione di markup più interna viene valutata per prima. È pertanto possibile presupporre tale utilizzo e dichiarare uno dei parametri della costruzione come tipo che richiede un convertitore di valori, quale un'estensione di markup, da produrre.

Nell'esempio precedente viene illustrato l'affidamento su tale elaborazione. Il writer dell'oggetto XAML dei servizi XAML di .NET Framework elabora i nomi delle costanti di enumerazione in valori enumerati a livello nativo.

L'elaborazione della sintassi del testo di un parametro posizionale dell'estensione di markup può inoltre basarsi su un convertitore di tipi associato al tipo nell'argomento della costruzione.

Gli argomenti sono detti argomenti posizionali perché l'ordine in base al quale vengono rilevati i token nell'utilizzo corrisponde all'ordine posizionale del parametro del costruttore a cui sono assegnati. Si consideri ad esempio la firma del costruttore seguente:

public Collate(CollationMode collationMode, object collateThis) {...}

Un processore XAML prevede la presenza di due argomenti posizionali per questa estensione di markup. Per un utilizzo {Collate AlphaUp,{x:Reference circularFile}}, il token AlphaUp viene inviato al primo parametro e quindi valutato come costante denominata dell'enumerazione CollationMode. Il risultato dell'argomento x:Reference interno viene inviato al secondo parametro e valutato come oggetto.

Nelle regole specificate per XAML per la sintassi e l'elaborazione dell'estensione di markup, la virgola è il delimitatore degli argomenti, sia che gli argomenti siano argomenti posizionali o denominati.

Grado duplicato di argomenti posizionali

Se un writer di oggetti XAML rileva un utilizzo dell'estensione di markup con argomenti posizionali e sono presenti più argomenti del costruttore che accettano il numero di argomenti specificato (un grado duplicato), non si tratta necessariamente di un errore. Il comportamento dipende da un'impostazione del contesto dello schema XAML personalizzabile, SupportMarkupExtensionsWithDuplicateArity. Se SupportMarkupExtensionsWithDuplicateArity è true, un writer di oggetti XAML non genera un'eccezione solo per motivi di grado duplicato. Il comportamento oltre tale punto non è definito con precisione. Il presupposto di base per la progettazione è che il contesto dello schema disponga di informazioni sul tipo disponibili per i parametri specifici e possa tentare cast espliciti corrispondenti ai candidati duplicati per individuare la firma che potenzialmente costituisce la corrispondenza ottimale. È tuttavia possibile che venga generata un'eccezione se nessuna delle firme supera i test imposti da tale particolare contesto dello schema in esecuzione in un writer di oggetti XAML.

Per impostazione predefinita, SupportMarkupExtensionsWithDuplicateArity è false nell'oggetto XamlSchemaContext basato su CLR per i servizi XAML di .NET Framework. L'oggetto XamlObjectWriter predefinito, pertanto, genera eccezioni se rileva un utilizzo dell'estensione di markup con grado duplicato nei costruttori del tipo sottostante.

Argomenti denominati per un'estensione di markup personalizzata

Le estensioni di markup specificate da XAML possono inoltre utilizzare argomenti denominati per l'utilizzo. Al primo livello di suddivisione in token, la sintassi del testo è divisa in argomenti. La presenza di un segno di uguale (=) all'interno di qualsiasi argomento identifica tale argomento come argomento denominato. Tale argomento viene inoltre suddiviso in token in una coppia nome/valore. Il nome in questo caso denomina una proprietà impostabile pubblica del tipo di supporto dell'estensione di markup. Se si intende supportare l'utilizzo di argomenti denominati, sarà necessario fornire queste proprietà impostabili pubbliche. Le proprietà possono essere proprietà ereditate, fino a quando rimangono pubbliche.

Accesso al contesto del provider di servizi da un'implementazione dell'estensione di markup

I servizi disponibili sono gli stessi per qualsiasi convertitore di valori. L'unica differenza risiede nel modo in cui ogni convertitore di valori riceve il contesto del servizio. L'accesso ai servizi e i servizi disponibili sono illustrati nell'argomento Convertitori di tipi ed estensioni di markup per XAML.

Utilizzo dell'elemento proprietà di un'estensione di markup

Gli scenari per gli utilizzi di estensioni di markup sono spesso progettati attorno all'utilizzo dell'estensione di markup nell'utilizzo dell'attributo. Tuttavia, è anche potenzialmente possibile definire la classe sottostante in modo che supporti l'utilizzo dell'elemento proprietà.

Per supportare l'utilizzo dell'elemento proprietà dell'estensione di markup, definire un costruttore predefinito pubblico. Deve trattarsi di un costruttore di istanza, non di un costruttore statico. Tale presupposto è necessario in quanto un processore XAML deve in genere richiamare il costruttore predefinito in qualsiasi elemento oggetto elaborato dal markup, incluse le classi dell'estensione di markup come elementi oggetto. Nel caso di scenari avanzati, è possibile definire percorsi di costruzione non predefiniti per le classi. Per ulteriori informazioni, vedere Direttiva x:FactoryMethod. Tuttavia, non si devono utilizzare questi modelli per scopi di estensione di markup poiché questo rende molto più difficile l'individuazione del modello di utilizzo tanto per i progettisti quanto per gli utenti di markup non elaborato.

Associazione di attributi per un'estensione di markup personalizzata

Per supportare sia gli ambienti di progettazione sia determinati scenari dei writer di oggetti XAML, è necessario associare al tipo di supporto dell'estensione di markup diversi attributi CLR. Questi attributi indicano l'utilizzo dell'estensione di markup desiderato.

MarkupExtensionReturnTypeAttribute specifica le informazioni su Type per il tipo di oggetto restituito da ProvideValue. In base alla semplice firma, ProvideValue restituisce Object. Diversi consumer potrebbero però richiedere informazioni più precise sul tipo restituito, vale a dire:

  • Finestre di progettazione e IDE, potenzialmente in grado di fornire supporto dipendente dal tipo per gli utilizzi delle estensioni di markup.

  • Implementazioni avanzate di gestori SetMarkupExtension in classi di destinazione, che possono basarsi sulla reflection per determinare il tipo restituito di un'estensione di markup anziché creare un ramo in implementazioni di MarkupExtension specifiche note in base al nome.

Serializzazione degli utilizzi di estensioni di markup

Quando un writer di oggetti XAML elabora un utilizzo dell'estensione di markup e chiama ProvideValue, il contesto del metodo che è stato precedentemente un utilizzo dell'estensione di markup viene reso persistente nel flusso del nodo XAML, ma non nell'oggetto grafico. Nell'oggetto grafico viene mantenuto solo il valore. In presenza di scenari di progettazione o altri motivi che determinano la necessità di rendere persistente l'utilizzo dell'estensione di markup originale nell'output serializzato, sarà necessario progettare un'infrastruttura personalizzata per tenere traccia degli utilizzi delle estensioni di markup dal flusso del nodo XAML del percorso di caricamento. È possibile implementare il comportamento per ricreare gli elementi del flusso del nodo dal percorso di caricamento e riprodurli per i writer XAML per la serializzazione nel percorso di salvataggio, sostituendo il valore nella posizione appropriata del flusso del nodo.

Estensioni di markup nel flusso del nodo XAML

Se si utilizza un flusso del nodo XAML nel percorso di caricamento, un utilizzo dell'estensione di markup viene visualizzato come oggetto nel flusso del nodo.

Se l'utilizzo dell'estensione di markup utilizza argomenti posizionali, viene rappresentato come oggetto iniziale con un valore di inizializzazione. Come rappresentazione di testo approssimativa, il flusso del nodo sarà simile a quanto segue:

StartObject (XamlType è il tipo di definizione dell'estensione di markup, non il tipo restituito)

  StartMember (il nome di XamlMember è _InitializationText)

    Value (rappresenta gli argomenti posizionali sotto forma di stringa, inclusi i delimitatori frapposti)

  EndMember

EndObject

Un utilizzo dell'estensione di markup con argomenti denominati viene rappresentato come oggetto con membri dei nomi relativi, ognuno impostato con valori della stringa di testo.

In realtà, il richiamo dell'implementazione di ProvideValue di un'estensione di markup necessita del contesto dello schema XAML, poiché questo richiede il mapping dei tipi e la creazione di un'istanza del tipo di supporto dell'estensione di markup. Questo è un motivo per cui gli utilizzi dell'estensione di markup sono conservati in questo modo nei flussi del nodo dei servizi XAML di .NET Framework. La parte del reader di un percorso di caricamento spesso non ha a disposizione il contesto dello schema XAML necessario.

Se si utilizza un flusso del nodo XAML nel percorso di salvataggio, in genere la rappresentazione dell'oggetto grafico in genere non contiene alcun elemento che possa indicare che l'oggetto da serializzare fosse originariamente fornito da un utilizzo dell'estensione di markup e un risultato ProvideValue. Negli scenari che richiedono il salvataggio permanente degli utilizzi dell'estensione di markup per le sequenze di andata e ritorno e al contempo l'acquisizione di altre modifiche nell'oggetto grafico, è necessario ideare tecniche personalizzate per preservare la conoscenza di un utilizzo dell'estensione di markup dall'input XAML originale. Ad esempio, per ripristinare gli utilizzi dell'estensione di markup, potrebbe essere necessario utilizzare il flusso del nodo nel percorso di salvataggio oppure eseguire una sorta di unione tra XAML originale e XAML sottoposto a sequenza di andata e ritorno. Alcuni framework che implementano XAML, ad esempio WPF, utilizzano tipi intermedi (espressioni) per rappresentare i casi in cui gli utilizzi dell'estensione di markup hanno fornito i valori.

Vedere anche

Riferimenti

MarkupExtension

Concetti

Estensioni di markup e XAML WPF

Altre risorse

Convertitori di tipi ed estensioni di markup per XAML