Condividi tramite


Estensioni di markup e XAML WPF

Questo argomento presenta il concetto di estensioni di markup per XAML, incluse le regole di sintassi, lo scopo e il modello a oggetti di classe sottostante. Le estensioni di markup sono una funzionalità generale del linguaggio XAML e dell'implementazione .NET dei servizi XAML. In questo argomento vengono fornite informazioni dettagliate sulle estensioni di markup da usare in XAML WPF.

Processori XAML ed estensioni di markup

In generale, un parser XAML può interpretare un valore dell'attributo come stringa letterale che può essere convertita in una primitiva o convertirla in un oggetto con alcuni mezzi. Uno di questi mezzi consiste nel fare riferimento a un convertitore di tipi; questo argomento è documentato nell'argomento TypeConverters e XAML. Esistono tuttavia scenari in cui è necessario un comportamento diverso. Ad esempio, a un processore XAML può essere istruito che il valore di un attributo non deve comportare la creazione di un nuovo oggetto nella gerarchia degli oggetti. L'attributo deve invece generare un oggetto grafico che fa riferimento a un oggetto già costruito in un'altra parte del grafico o a un oggetto statico. Un altro scenario è che un processore XAML può essere richiesto di usare una sintassi che fornisce argomenti non predefiniti al costruttore di un oggetto. Questi sono i tipi di scenari in cui un'estensione di markup può fornire la soluzione.

Sintassi di base dell'estensione di markup

È possibile implementare un'estensione di markup che possa fornire valori per le proprietà nell'utilizzo degli attributi, nell’utilizzo degli elementi proprietà, o entrambi.

Se usato per fornire un valore di attributo, la sintassi che distingue una sequenza di estensione di markup per un processore XAML è la presenza delle parentesi graffe di apertura e chiusura ({ e }). Il tipo di estensione di markup viene quindi identificato dalla stringa token immediatamente dopo la parentesi graffa di apertura.

Quando viene usata nella sintassi degli elementi di proprietà, un'estensione di markup è visivamente uguale a qualsiasi altro elemento usato per fornire un valore dell'elemento proprietà: una dichiarazione di elemento XAML che fa riferimento alla classe di estensione di markup come elemento, racchiuso tra parentesi angolari (<>).

Estensioni di markup XAML-Defined

Esistono diverse estensioni di markup non specifiche per l'implementazione WPF di XAML, ma sono invece implementazioni di intrinseci o funzionalità di XAML come linguaggio. Queste estensioni di markup vengono implementate nell'assembly System.Xaml come parte dei servizi XAML di .NET Framework generali e si trovano nello spazio dei nomi XAML del linguaggio XAML. In termini di utilizzo comune del markup, queste estensioni di markup sono in genere identificabili dal prefisso x: nella loro applicazione. La MarkupExtension classe base (definita anche in System.Xaml) fornisce il modello che tutte le estensioni di markup devono usare per essere supportate nei lettori XAML e nei writer XAML, incluso in XAML WPF.

  • x:Type fornisce l'oggetto Type per il tipo denominato. Questa funzionalità viene usata più frequentemente negli stili e nei modelli. Per informazioni dettagliate, vedere Estensione di markup x:Type.

  • x:Static produce valori statici. I valori provengono da entità di codice di tipo valore che non sono direttamente il tipo del valore di una proprietà di destinazione, ma possono essere valutati in tale tipo. Per ulteriori dettagli, consultare x:Static Markup Extension.

  • x:Null null specifica come valore per una proprietà e può essere usato per gli attributi o i valori degli elementi di proprietà. Per informazioni dettagliate, vedere Estensione di markup x:Null.

  • x:Array fornisce supporto per la creazione di matrici generali nella sintassi XAML, nei casi in cui il supporto della raccolta fornito dagli elementi di base e dai modelli di controllo WPF non viene usato intenzionalmente. Per informazioni dettagliate, vedere Estensione di markup x:Array.

Annotazioni

Il prefisso x: viene utilizzato per la mappatura tipica del namespace del linguaggio XAML, comprendente le caratteristiche intrinseche, nell'elemento radice di un file o di una produzione XAML. Ad esempio, i modelli di Visual Studio per le applicazioni WPF avviano un file XAML usando questo x: mapping. È possibile scegliere un token di prefisso diverso nel mapping dello spazio dei nomi XAML, ma questa documentazione presuppone il mapping predefinito x: come mezzo per identificare le entità che sono una parte definita dello spazio dei nomi XAML per il linguaggio XAML, anziché lo spazio dei nomi predefinito WPF o altri spazi dei nomi XAML non correlati a un framework specifico.

Estensioni di markup WPF-Specific

Le estensioni di markup più comuni usate nella programmazione WPF sono quelle che supportano riferimenti alle risorse (StaticResource e DynamicResource) e quelle che supportano il data binding (Binding).

  • StaticResource fornisce un valore per una proprietà sostituendo il valore di una risorsa già definita. Una StaticResource valutazione viene infine eseguita in fase di caricamento XAML e non ha accesso all'oggetto grafico in fase di esecuzione. Per informazioni dettagliate, vedere StaticResource Markup Extension.

  • DynamicResource fornisce un valore per una proprietà rinviando tale valore come riferimento di runtime a una risorsa. Un riferimento di risorsa dinamica richiede una nuova ricerca ogni volta che si accede a una risorsa di questo tipo e ha accesso al grafico degli oggetti in fase di esecuzione. Per ottenere questo accesso, DynamicResource il concetto è supportato dalle proprietà di dipendenza nel sistema di proprietà WPF e dalle espressioni valutate. Pertanto, è possibile usare DynamicResource solo per una destinazione della proprietà di dipendenza. Per informazioni dettagliate, vedere Estensione di markup DynamicResource.

  • Binding fornisce un valore associato a dati per una proprietà, utilizzando il contesto dati applicabile all'oggetto padre in fase di esecuzione. Questa estensione di markup è relativamente complessa, perché consente una sintassi inline sostanziale per specificare un data binding. Per informazioni dettagliate, vedere Binding Markup Extension.

  • RelativeSource fornisce informazioni di origine per un oggetto Binding in grado di esplorare diverse relazioni possibili nell'albero degli oggetti di runtime. In questo modo vengono fornite fonti specializzate per le associazioni create in modelli multi-uso o create tramite codice senza conoscere in modo completo la struttura ad albero degli oggetti circostanti. Per informazioni dettagliate, vedere RelativeSource MarkupExtension.

  • TemplateBinding consente a un modello di controllo di usare valori per le proprietà basate su modelli provenienti da proprietà definite dal modello a oggetti della classe che userà il modello. In altre parole, la proprietà all'interno della definizione del modello può accedere a un contesto esistente solo dopo l'applicazione del modello. Per maggiori dettagli, consultare Estensione di markup TemplateBinding. Per ulteriori informazioni sull'uso pratico di TemplateBinding, vedere l'esempio Esempio di stile con ControlTemplates.

  • ColorConvertedBitmap supporta uno scenario di imaging relativamente avanzato. Per informazioni dettagliate, vedere ColorConvertedBitmap Markup Extension.

  • ComponentResourceKey e ThemeDictionary supportano gli aspetti della ricerca delle risorse, in particolare per le risorse e i temi inclusi in pacchetti con controlli personalizzati. Per altre informazioni, vedere ComponentResourceKey Markup Extension, ThemeDictionary Markup Extension o Control Authoring Overview.For more information, see ComponentResourceKey Markup Extension, ThemeDictionary Markup Extension, or Control Authoring Overview.

*Classi di estensione

Sia per il linguaggio XAML generale che per le estensioni di markup specifiche di WPF, il comportamento di ogni estensione di markup viene identificato in un processore XAML tramite una *Extension classe che deriva da MarkupExtensione fornisce un'implementazione del ProvideValue metodo . Questo metodo in ogni estensione fornisce l'oggetto restituito quando viene valutata l'estensione di markup. L'oggetto restituito viene generalmente valutato sulla base dei vari token di stringa che vengono passati all'estensione di markup.

Ad esempio, la classe StaticResourceExtension fornisce l'implementazione della ricerca effettiva delle risorse in modo che la sua implementazione ProvideValue restituisca l'oggetto richiesto, utilizzando una stringa specifica che viene usata per cercare la risorsa in base al suo x:Key. Gran parte di questo dettaglio di implementazione non è importante se si usa un'estensione di markup esistente.

Alcune estensioni di markup non usano argomenti di token stringa. Ciò è dovuto al fatto che restituiscono un valore statico o coerente oppure perché il contesto per quale valore deve essere restituito è disponibile tramite uno dei servizi passati tramite il serviceProvider parametro .

Il *Extension modello di denominazione è per praticità e coerenza. Non è necessario per consentire a un processore XAML di identificare tale classe come supporto per un'estensione di markup. Purché la codebase includa System.Xaml e usi le implementazioni dei servizi XAML di .NET Framework, tutto ciò che è necessario per essere riconosciuto come estensione di markup XAML consiste nel derivare da MarkupExtension e per supportare una sintassi di costruzione. WPF definisce classi di abilitazione dell'estensione di markup che non seguono il *Extension modello di denominazione, ad esempio Binding. In genere, il motivo è che la classe supporta scenari oltre al supporto puro dell'estensione di markup. Nel caso di Binding, tale classe supporta l'accesso in fase di esecuzione ai metodi e alle proprietà dell'oggetto per scenari non correlati a XAML.

Interpretazione della Classe di Estensione del Testo Iniziale

I token stringa che seguono il nome dell'estensione di markup e ancora all'interno delle parentesi graffe vengono interpretati da un processore XAML in uno dei modi seguenti:

  • Una virgola rappresenta sempre il separatore o il delimitatore dei singoli token.

  • Se i singoli token separati non contengono segni di uguale, ogni token viene considerato come un argomento del costruttore. Ogni parametro del costruttore deve essere assegnato come tipo previsto da tale firma e nell'ordine corretto previsto da tale firma.

    Annotazioni

    Un processore XAML deve chiamare il costruttore che corrisponde al conteggio degli argomenti delle coppie. Per questo motivo, se implementi un'estensione di markup personalizzata, non fornire più costruttori con lo stesso numero di argomenti. Il comportamento di un processore XAML se esiste più di un percorso del costruttore dell'estensione di markup con lo stesso conteggio di parametri, il comportamento non è definito, ma dovresti anticipare che un processore XAML sia consentito di generare un'eccezione durante l'uso se questa situazione si verifica nelle definizioni dei tipi di estensione di markup.

  • Se i singoli token separati contengono segni di uguale, un processore XAML chiama prima il costruttore senza parametri dell'estensione di markup. Ogni coppia name=value viene quindi interpretata come un nome di proprietà esistente nell'estensione di markup e un valore da assegnare a tale proprietà.

  • Se esiste un risultato parallelo tra il comportamento del costruttore e il comportamento dell'impostazione della proprietà in un'estensione di markup, non è importante quale comportamento si usa. È più comune usare le coppie proprietà-= per le estensioni di markup che hanno più proprietà impostabili, anche solo perché rende il markup più intenzionale ed è meno probabile che trasponi accidentalmente i parametri del costruttore. Quando si specificano coppie property=value, tali proprietà possono essere in qualsiasi ordine. Inoltre, non esiste alcuna garanzia che un'estensione di markup fornisca un parametro del costruttore che imposta ogni proprietà impostabile. Ad esempio, Binding è un'estensione di markup, con molte proprietà che sono impostabili tramite l'estensione nel formato proprietà=valore, ma Binding supporta solo due costruttori: un costruttore senza parametri e uno che imposta un percorso iniziale.

  • Non è possibile passare una virgola letterale a un'estensione di markup senza escape.

Sequenze di escape ed estensioni di markup

La gestione degli attributi in un processore XAML utilizza le parentesi graffe come indicatori di una sequenza di estensione del markup. È anche possibile produrre un valore di attributo letterale per il carattere parentesi graffa, se necessario, immettendo una sequenza di escape utilizzando una coppia di parentesi graffe vuote seguita dalla parentesi graffa letterale. Vedere {} Sequenza di escape - Estensione di markup.

Annidamento delle estensioni di markup nell'utilizzo di XAML

L'annidamento di più estensioni di markup è supportato e ciascuna estensione di markup verrà valutata partendo dalla più interna. Si consideri ad esempio l'utilizzo seguente:

<Setter Property="Background"
  Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />

In questo utilizzo, l'istruzione x:Static viene valutata per prima e restituisce una stringa. Tale stringa viene quindi usata come argomento per DynamicResource.

Estensioni di markup e sintassi degli elementi property

Quando viene utilizzato come elemento dell'oggetto che riempie un valore di un elemento di proprietà, una classe di estensione di markup è visivamente indistinguibile da un elemento dell'oggetto tipico sostenuto da un tipo specifico che può essere utilizzato in XAML. La differenza pratica tra un elemento oggetto tipico e un'estensione di markup è che l'estensione di markup viene valutata in un valore tipizzato o posticipata come espressione. Di conseguenza, i meccanismi per eventuali errori di tipo dei valori delle proprietà per l'estensione di markup saranno diversi, analogamente al modo in cui una proprietà con binding ritardato viene trattata in altri modelli di programmazione. Quando viene elaborato il XAML, un elemento oggetto ordinario verrà valutato per la corrispondenza del tipo rispetto alla proprietà di destinazione che sta impostando.

La maggior parte delle estensioni di markup, se utilizzata nella sintassi degli elementi oggetto per riempire un elemento di proprietà, non avrebbe contenuto o qualsiasi altra sintassi degli elementi di proprietà all'interno. In questo modo si chiude il tag dell'elemento oggetto e non si specifica alcun elemento figlio. Ogni volta che viene rilevato un elemento oggetto da un processore XAML, viene chiamato il costruttore per tale classe, che crea un'istanza dell'oggetto creato dall'elemento analizzato. Una classe di estensione di markup non è diversa: se si vuole che l'estensione di markup sia utilizzabile nella sintassi degli elementi oggetto, è necessario fornire un costruttore senza parametri. Alcune estensioni di markup esistenti hanno almeno un valore di proprietà obbligatorio che deve essere specificato per l'inizializzazione efficace. In tal caso, tale valore della proprietà viene in genere assegnato come attributo di proprietà sull'elemento dell'oggetto. Nelle pagine di riferimento delle funzionalità del linguaggio dello spazio dei nomi XAML (x:) e delle estensioni XAML WPF, verranno annotate le estensioni di markup con proprietà obbligatorie (e i nomi delle proprietà obbligatorie). Le pagine di riferimento noteranno anche se la sintassi dell'elemento oggetto o la sintassi dell'attributo non è consentita per specifiche estensioni di markup. Un caso rilevante è x:Array Markup Extension, che non può supportare la sintassi dell'attributo perché il contenuto di tale matrice deve essere specificato all'interno dell'assegnazione di tag come contenuto. Il contenuto della matrice viene gestito come oggetti generali, pertanto non è possibile usare alcun convertitore di tipi predefinito per l'attributo. Inoltre, l'estensione di markup x:Array richiede un type parametro .

Vedere anche