TypeConverter e XAML

Questo argomento illustra lo scopo della conversione del tipo string come funzionalità generale del linguaggio XAML. In .NET Framework la TypeConverter classe funge da scopo specifico come parte dell'implementazione di una classe personalizzata gestita che può essere usata come valore della proprietà nell'utilizzo degli attributi XAML. Se scrivi una classe personalizzata e vuoi che le istanze della classe siano utilizzabili come valori di attributo impostabili XAML, potresti dover applicare un oggetto TypeConverterAttribute alla classe, scrivere una classe personalizzata TypeConverter o entrambi.

Concetti relativi alla conversione di tipi

Valori XAML e stringa

Quando si imposta un valore di attributo in un file XAML, il tipo iniziale di tale valore è una stringa di solo testo. Anche altre primitive, Double ad esempio, sono inizialmente stringhe di testo a un processore XAML.

Un processore XAML necessita di due informazioni per elaborare un valore di attributo. La prima informazione è il tipo di valore della proprietà che si imposta. Qualsiasi stringa che definisce un valore di attributo e che viene elaborata in XAML deve essere convertita o risolta in un valore di quel tipo. Se il valore è una primitiva riconosciuta dal parser XAML (ad esempio un valore numerico), viene tentata una conversione diretta della stringa. Se il valore è un'enumerazione, la stringa viene usata per controllare la corrispondenza di un nome con una costante denominata in tale enumerazione. Se il valore non è né una primitiva riconosciuta dal parser né un'enumerazione, il tipo in questione deve essere in grado di fornire un'istanza del tipo o un valore basato su una stringa convertita. Ciò è possibile indicando una classe di convertitore di tipi. Il convertitore di tipi è una classe helper che fornisce valori di un'altra classe, sia per gli scenari XAML che, potenzialmente, per le chiamate nel codice .NET.

Uso del comportamento di conversione dei tipi esistente in XAML

A seconda del livello di conoscenza dei concetti XAML sottostanti, è possibile che si usi già il comportamento di conversione dei tipi nel codice XAML dell'applicazione di base senza rendersene conto. Ad esempio, WPF definisce letteralmente centinaia di proprietà che accettano un valore di tipo Point. Un Point è un valore che descrive una coordinata in uno spazio di coordinate bidimensionale e ha in realtà solo due proprietà importanti: X e Y. Quando specifichi un punto in XAML, lo specifichi come stringa con un delimitatore (in genere una virgola) tra i X valori e Y specificati. Ad esempio: <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"/>.

Anche questo semplice tipo di Point e il suo utilizzo semplice in XAML comportano un convertitore di tipi. In questo caso è la classe PointConverter.

Il convertitore di tipi per Point definito a livello di classe semplifica gli utilizzi di markup di tutte le proprietà che accettano Point. Senza un convertitore di tipi, per l'esempio illustrato in precedenza sarebbe necessario ricorrere al seguente markup molto più dettagliato:

<LinearGradientBrush>
  <LinearGradientBrush.StartPoint>
    <Point X="0" Y="0"/>
  </LinearGradientBrush.StartPoint>
  <LinearGradientBrush.EndPoint>
    <Point X="1" Y="1"/>
  </LinearGradientBrush.EndPoint>
</LinearGradientBrush>

La scelta tra l'uso di una stringa di conversione del tipo o di una sintassi equivalente più dettagliata è, in genere, una questione di stile di codifica. Anche il flusso di lavoro degli strumenti XAML può influire sul modo in cui vengono impostati i valori. Alcuni strumenti XAML tendono a generare la forma più dettagliata del markup perché è più facile eseguire il round trip nelle visualizzazioni delle finestre di progettazione o nel meccanismo di serializzazione.

I convertitori di tipi esistenti possono in genere essere individuati nei tipi WPF e .NET Framework controllando una classe (o una proprietà) per la presenza di un oggetto applicato TypeConverterAttribute. Questo attributo assegnerà un nome alla classe che costituisce il convertitore di tipi di supporto per i valori del tipo in questione, sia per gli scenari XAML sia, eventualmente, per altri scopi.

Convertitori di tipi ed estensioni di markup

Le estensioni di markup e i convertitori di tipi rivestono ruoli ortogonali in termini di comportamento del processore XAML e di scenari ai cui sono applicati. Anche se il contesto è disponibile per gli utilizzi di estensione di markup, il comportamento della conversione di tipi di proprietà in cui un'estensione di markup fornisce un valore in genere non è selezionato nelle implementazioni dell'estensione di markup. In altre parole, anche se un'estensione di markup restituisce una stringa di testo come output di ProvideValue, il comportamento di conversione dei tipi su tale stringa così come applicato a una proprietà o a un tipo di valore della proprietà specifico non viene richiamato. In genere, lo scopo di un'estensione di markup è quello di elaborare una stringa e restituire un oggetto senza coinvolgere alcun convertitore di tipi.

Una situazione comune che richiede un'estensione di markup invece che un convertitore di tipi è il riferimento a un oggetto già esistente. Nella migliore delle ipotesi, un convertitore di tipi senza stato può solo generare una nuova istanza, che potrebbe non essere il comportamento ottimale. Per altre informazioni sulle estensioni di markup, vedere Estensioni di markup e XAML WPF.

Convertitori di tipi nativi

Nell'implementazione WPF e .NET Framework del parser XAML ci sono determinati tipi che prevedono la gestione nativa della conversione del tipo, anche se non si tratta di tipi convenzionalmente considerati primitive. Un esempio dei tipi in questione è DateTime. Il motivo è basato sul funzionamento dell'architettura di .NET Framework: il tipo DateTime è definito in mscorlib, la libreria più semplice in .NET. DateTime non è consentito l'attributo con un attributo proveniente da un altro assembly che introduce una dipendenza (TypeConverterAttribute proviene da System), quindi il consueto meccanismo di individuazione del convertitore di tipi tramite l'attributo non può essere supportato. Il parser XAML ha invece di un elenco di tipi che necessitano di tale elaborazione nativa ed elabora questi tipi in modo analogo all'elaborazione delle primitive effettive. (Nel caso di DateTime questo comporta una chiamata a Parse.)

Implementazione di un convertitore di tipi

TypeConverter

Nell'esempio Point specificato in precedenza, la classe PointConverter è stata menzionata. Per le implementazioni .NET di XAML, tutti i convertitori di tipi usati a scopo XAML sono classi che derivano dalla classe TypeConverterbase . La TypeConverter classe esisteva nelle versioni di .NET Framework che precedevano l'esistenza di XAML. Uno dei relativi utilizzi originali era quello di fornire la conversione di stringhe per le finestre di dialogo delle proprietà nelle finestre di progettazione degli oggetti visivi. Per XAML, il ruolo di viene espanso per includere la classe base per le conversioni da stringa a stringa e da stringa che consentono di analizzare un valore di TypeConverter attributo stringa ed eventualmente di elaborare un valore di run-time di una particolare proprietà dell'oggetto in una stringa per la serializzazione come attributo.

TypeConverter definisce quattro membri rilevanti per la conversione da e verso stringhe a scopo di elaborazione XAML:

Di questi, il metodo più importante è ConvertFrom. Questo metodo converte la stringa di input nel tipo di oggetto richiesto. In senso stretto, il ConvertFrom metodo può essere implementato per convertire una gamma molto più ampia di tipi nel tipo di destinazione previsto del convertitore e quindi servire scopi che si estendono oltre XAML, ad esempio supportando le conversioni in fase di esecuzione, ma ai fini XAML è solo il percorso del codice che può elaborare un String input importante.

Il metodo più importante successivo è ConvertTo. Se un'applicazione viene convertita in una rappresentazione di markup (ad esempio, se viene salvata in XAML come file), ConvertTo è responsabile della produzione di una rappresentazione di markup. In questo caso, il percorso del codice importante per XAML è quando si passa un destinationType di String .

CanConvertTo e CanConvertFrom sono metodi di supporto usati quando un servizio esegue una query sulle funzionalità dell'implementazione di TypeConverter . È necessario implementare questi metodi per restituire true per i casi specifici del tipo supportati dai metodi di conversione equivalenti del convertitore. Per XAML, si tratta in genere del tipo String .

Informazioni relative alle impostazioni cultura e convertitori di tipi per XAML

Ogni TypeConverter implementazione può avere una propria interpretazione di ciò che costituisce una stringa valida per una conversione e può anche usare o ignorare la descrizione del tipo passata come parametri. C'è un'importante considerazione per quanto riguarda le impostazioni cultura e la conversione di tipi in XAML. L'uso di stringhe localizzabili come valori di attributo è completamente supportato in XAML. L'uso di una stringa localizzabile come input del convertitore di tipi con requisiti di impostazioni cultura specifici non è però supportato, perché i convertitori di tipi per i valori di attributi XAML implicano un comportamento di analisi basato su un'unica lingua e sulle impostazioni cultura en-US. Per altre informazioni sui motivi di progettazione per questa restrizione, consulta la specifica del linguaggio XAML ([MS-XAML].

Un caso in cui le impostazioni cultura possono rappresentare un problema è ad esempio l'uso, in alcune impostazioni cultura, della virgola come separatore decimale per i numeri. Tale caratteristica è in conflitto con il comportamento di molti convertitori di tipi XAML di WPF, che usano la virgola come delimitatore (in base a precedenti storici come il formato X,Y comune o gli elenchi delimitati da virgole). Nemmeno il passaggio di impostazioni cultura nel codice XAML adiacente (impostando ad esempio Language o xml:lang sulle impostazioni cultura sl-SI che prevedono l'uso della virgola come separatore decimale) può consentire di risolvere il problema.

Implementazione di ConvertFrom

Per essere utilizzabile come implementazione di TypeConverter che supporti XAML, il metodo ConvertFrom per il convertitore deve accettare una stringa come parametro value . Se la stringa era in formato valido e può essere convertita dall'implementazione, l'oggetto TypeConverter restituito deve supportare un cast al tipo previsto dalla proprietà . In caso contrario, l'implementazione ConvertFrom deve restituire null.

Ogni TypeConverter implementazione può avere una propria interpretazione di ciò che costituisce una stringa valida per una conversione e può anche usare o ignorare i contesti di descrizione o impostazioni cultura del tipo passati come parametri. L'elaborazione della sintassi XAML di WPF potrebbe tuttavia non passare i valori al contesto della descrizione del tipo in tutti i casi e potrebbe non passare nemmeno le impostazioni cultura basate su xml:lang.

Nota

Non usare i caratteri parentesi graffa, in particolare {, come elemento del formato stringa. Questi caratteri vengono usati esclusivamente come punti di ingresso e di uscita di una sequenza di estensione del markup.

Implementazione di ConvertTo

ConvertTo viene potenzialmente usato per il supporto della serializzazione. Il supporto della serializzazione tramite ConvertTo per il tipo personalizzato e il relativo convertitore di tipi non è un requisito assoluto. Tuttavia, se si implementa un controllo o si usa la serializzazione come parte delle funzionalità o della progettazione della classe, sarà necessario implementare ConvertTo.

Per essere utilizzabile come TypeConverter implementazione che supporta XAML, il ConvertTo metodo per tale convertitore deve accettare un'istanza del tipo (o un valore) supportata come value parametro. Quando il destinationType parametro è il tipo String, l'oggetto restituito deve essere in grado di eseguire il cast come String. La stringa restituita deve rappresentare un valore serializzato di value. Idealmente, il formato di serializzazione scelto dovrebbe essere in grado di generare lo stesso valore se tale stringa è stata passata all'implementazione ConvertFrom dello stesso convertitore, senza perdita significativa di informazioni.

Se il valore non può essere serializzato o il convertitore non supporta la serializzazione, l'implementazione ConvertTo deve restituire nulle può generare un'eccezione in questo caso. Tuttavia, se si generano eccezioni, è consigliabile segnalare l'impossibilità di usare tale conversione come parte dell'implementazione CanConvertTo in modo che la procedura consigliata di controllare con CanConvertTo prima per evitare eccezioni sia supportata.

Se destinationType il parametro non è di tipo String, è possibile scegliere la gestione del convertitore personalizzata. In genere, si ripristina la gestione dell'implementazione di base, che nella base più ConvertTo genera un'eccezione specifica.

Implementazione di CanConvertTo

L'implementazione di CanConvertTo deve restituire true per un oggetto destinationType di tipo String; in caso contrario, deve rinviare all'implementazione di base.

Implementazione di CanConvertFrom

L'implementazione di CanConvertFrom deve restituire true per un oggetto sourceType di tipo String; in caso contrario, deve rinviare all'implementazione di base.

Applicazione di TypeConverterAttribute

Affinché il convertitore di tipi personalizzato venga usato come convertitore di tipi agendo per una classe personalizzata da un processore XAML, devi applicare alla definizione della TypeConverterAttribute classe. L'oggetto ConverterTypeName specificato tramite l'attributo deve corrispondere al nome di tipo del convertitore dei tipi personalizzato. Se si applica questo attributo, quando un processore XAML gestisce valori per i quali il tipo di proprietà usa il tipo di classe personalizzato, può usare stringhe di input e restituire istanze di oggetti.

Si può anche fornire un convertitore dei tipi per le singole proprietà. Anziché applicare un TypeConverterAttribute alla definizione della classe, applicarlo a una definizione della proprietà (la definizione principale, non le implementazioni di get/set al suo interno). Il tipo della proprietà deve corrispondere al tipo elaborato dal convertitore dei tipi personalizzato. Se questo attributo viene applicato, quando un processore XAML gestisce i valori di quella proprietà, può elaborare stringhe di input e restituire istanze di oggetti. La tecnica del convertitore di tipi per proprietà è particolarmente utile se si sceglie di usare un tipo di proprietà da Microsoft .NET Framework o da un'altra libreria in cui non è possibile controllare la definizione della classe e non è possibile applicare un oggetto TypeConverterAttribute .

Vedi anche