TypeConverters e XAML
Este tópico apresenta a finalidade da conversão de tipo da cadeia de caracteres como um recurso de linguagem XAML geral. No .NET Framework, a classe TypeConverter serve a uma finalidade específica como parte da implementação de uma classe personalizada gerenciada que pode ser usada como um valor de propriedade no uso do atributo XAML. Se você escrever uma classe personalizada e quiser que instâncias de sua classe sejam utilizáveis como valores de atributo configuráveis em XAML, talvez seja necessário aplicar um TypeConverterAttribute à sua classe, escrever uma classe de TypeConverter personalizada ou ambas.
Conceitos de conversão de tipo
Valores de XAML e cadeia de caracteres
Quando você define um valor de atributo em um arquivo XAML, o tipo inicial desse valor é uma cadeia de caracteres em texto puro. Mesmo outros primitivos, como Double, são inicialmente cadeias de caracteres de texto para um processador XAML.
Um processador XAML precisa de duas informações para processar um valor de atributo. A primeira parte das informações é o tipo de valor da propriedade que está sendo definida. Qualquer cadeia de caracteres que defina um valor de atributo e que seja processada em XAML deve, em última análise, ser convertida ou resolvida em um valor desse tipo. Se o valor for um primitivo compreendido pelo analisador XAML (como um valor numérico), uma conversão direta da cadeia de caracteres será tentada. Se o valor for uma enumeração, a cadeia de caracteres será usada para verificar se um nome corresponde a uma constante nomeada nessa enumeração. Se o valor não for um primitivo compreendido pelo analisador nem uma enumeração, o tipo em questão deverá ser capaz de fornecer uma instância do tipo ou um valor, com base em uma cadeia de caracteres convertida. Isso é feito indicando uma classe de conversor de tipo. O conversor de tipo é efetivamente uma classe auxiliar para fornecer valores de outra classe, tanto para o cenário XAML quanto para chamadas de código no código .NET.
Usando o comportamento de conversão de tipo existente em XAML
Dependendo de sua familiaridade com os conceitos de XAML subjacentes, talvez você já esteja usando o comportamento de conversão de tipo no XAML básico do aplicativo sem perceber. Por exemplo, o WPF define literalmente centenas de propriedades que levam um valor do tipo Point. Um Point é um valor que descreve uma coordenada em um espaço de coordenada bidimensional e tem apenas duas propriedades importantes: X e Y. Ao especificar um ponto em XAML, especifique-o como uma cadeia de caracteres com um delimitador (normalmente uma vírgula) entre os valores X e Y fornecidos. Por exemplo: <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"/>
.
Mesmo esse tipo simples de Point e seu uso simples no XAML envolvem um conversor de tipo. Nesse caso, essa é a classe PointConverter.
O conversor de tipo para Point definido no nível da classe simplifica o uso de marcações em todas as propriedades que aceitam Point. Sem um conversor de tipo aqui, você precisaria da seguinte marcação muito mais detalhada para o mesmo exemplo mostrado anteriormente:
<LinearGradientBrush>
<LinearGradientBrush.StartPoint>
<Point X="0" Y="0"/>
</LinearGradientBrush.StartPoint>
<LinearGradientBrush.EndPoint>
<Point X="1" Y="1"/>
</LinearGradientBrush.EndPoint>
</LinearGradientBrush>
Usar a string de conversão de tipo ou uma sintaxe equivalente mais verbosa geralmente é uma escolha de estilo de codificação. Seu fluxo de trabalho de ferramentas XAML também pode influenciar como os valores são definidos. Algumas ferramentas XAML tendem a emitir a forma mais detalhada da marcação porque é mais fácil converter para visualizações de design ou para seu próprio mecanismo de serialização.
Conversores de tipo existentes geralmente podem ser encontrados em tipos WPF e .NET Framework verificando-se se uma classe (ou propriedade) tem um TypeConverterAttributeaplicado. Esse atributo nomeará a classe que atua como conversor de tipos auxiliar para valores dessa classe, tanto para fins de XAML quanto, potencialmente, para outras finalidades.
Conversores de tipo e extensões de marcação
Extensões de marcação e conversores de tipo preenchem funções ortogonais em termos de comportamento do processador XAML e dos cenários aos quais são aplicados. Embora o contexto esteja disponível para usos de extensão de marcação, o comportamento de conversão de tipo de propriedades onde uma extensão de marcação fornece um valor não é geralmente verificado nas implementações de extensão de marcação. Em outras palavras, mesmo que uma extensão de marcação retorne uma cadeia de caracteres de texto como sua saída ProvideValue
, o comportamento de conversão de tipo nessa cadeia de caracteres, quando aplicado a uma propriedade específica ou tipo de valor de propriedade, não é invocado. Geralmente, a finalidade de uma extensão de marcação é processar uma cadeia de caracteres e retornar um objeto sem envolver um conversor de tipo.
Uma situação comum em que uma extensão de marcação é necessária em vez de um conversor de tipo é fazer uma referência a um objeto que já existe. Na melhor das hipóteses, um conversor de tipo sem estado só poderia gerar uma nova instância, o que pode não ser desejável. Para obter mais informações sobre extensões de marcação, consulte Extensões de Marcação eXAML do WPF.
Conversores de tipo nativos
Na implementação do WPF e do .NET Framework do analisador XAML, há certos tipos que têm tratamento de conversão de tipo nativo, mas não são tipos que podem ser considerados convencionalmente como primitivos. Um exemplo desse tipo é DateTime. O motivo disso é baseado em como a arquitetura do .NET Framework funciona: o tipo DateTime é definido no mscorlib, a biblioteca mais básica do .NET. DateTime não pode ser atribuído com um atributo que venha de outro assembly que introduza uma dependência (TypeConverterAttribute é do System), portanto, o mecanismo usual de descoberta de conversor de tipo por meio de atributos não pode ser suportado. Em vez disso, o analisador XAML tem uma lista de tipos que precisam desse processamento nativo e os processa de forma semelhante à forma como os primitivos verdadeiros são processados. (No caso de DateTime isso envolve uma chamada para Parse.)
Implementando um conversor de tipo
TypeConverter
No exemplo de Point dado anteriormente, a classe PointConverter foi mencionada. Para implementações do .NET de XAML, todos os conversores de tipo usados para fins XAML são classes que derivam da classe base TypeConverter. A classe TypeConverter existia em versões do .NET Framework que precedem a existência de XAML; um de seus usos originais era fornecer conversão de cadeia de caracteres para caixas de diálogo de propriedade em designers visuais. Para XAML, a função de TypeConverter é expandida para incluir ser a classe base para conversões para e a partir de cadeia de caracteres, que permitem analisar um valor de atributo de cadeia de caracteres e, possivelmente, processar um valor em tempo de execução de uma propriedade específica de objeto de volta para uma cadeia de caracteres para serialização como um atributo.
TypeConverter define quatro membros relevantes para converter de e para cadeias de caracteres para fins de processamento XAML:
Destes, o método mais importante é ConvertFrom. Esse método converte a cadeia de caracteres de entrada no tipo de objeto necessário. Estritamente falando, o método ConvertFrom poderia ser implementado para converter uma gama muito maior de tipos no tipo de destino pretendido do conversor e, portanto, servir para fins que se estendem além do XAML, como dar suporte a conversões em tempo de execução, mas para fins XAML é apenas o caminho de código que pode processar uma entrada String que importa.
O próximo método mais importante é ConvertTo. Se um aplicativo for convertido em uma representação de marcação (por exemplo, se ele for salvo em XAML como um arquivo), ConvertTo será responsável por produzir uma representação de marcação. Nesse caso, o caminho de código que importa para XAML é quando você passa uma destinationType
de String .
CanConvertTo e CanConvertFrom são métodos de suporte usados quando um serviço consulta os recursos da implementação do TypeConverter. Você deve implementar esses métodos para retornar true
para casos específicos de tipos que os métodos de conversão equivalentes do seu conversor suportam. Para fins XAML, isso geralmente significa o tipo String.
Informações de cultura e conversores de tipo para XAML
Cada TypeConverter implementação pode ter sua própria interpretação do que constitui uma cadeia de caracteres válida para uma conversão e também pode usar ou ignorar a descrição do tipo passada como parâmetros. É importante considerar a relação entre cultura e a conversão de tipos XAML. O uso de cadeias de caracteres localizáveis como valores de atributo é totalmente compatível com XAML. Mas não há suporte para o uso dessa cadeia de caracteres localizável como entrada de conversor de tipo com requisitos de cultura específicos, pois conversores de tipo para valores de atributo XAML envolvem um comportamento de análise de linguagem necessariamente fixa, usando en-US
cultura. Para obter mais informações sobre os motivos de design dessa restrição, consulte a especificação da linguagem XAML ([MS-XAML].
Como um exemplo em que a cultura pode ser um problema, algumas culturas usam uma vírgula como delimitador de ponto decimal para números. Isso colidirá com o comportamento que muitos dos conversores de tipo XAML do WPF têm, que é usar uma vírgula como delimitador (com base em precedentes históricos, como o formulário X,Y comum ou listas delimitadas por vírgula). Mesmo passar uma cultura no XAML ao redor (configurando Language
ou xml:lang
para a cultura sl-SI
, um exemplo de uma cultura que usa uma vírgula para decimal dessa forma) não resolve o problema.
Implementando ConvertFrom
Para ser utilizável como uma implementação TypeConverter que dá suporte a XAML, o método ConvertFrom para esse conversor deve aceitar uma cadeia de caracteres como o parâmetro value
. Se a cadeia de caracteres estiver em formato válido e puder ser convertida pela implementação TypeConverter, o objeto retornado deverá dar suporte a uma conversão para o tipo esperado pela propriedade. Caso contrário, a implementação do ConvertFrom deve retornar null
.
Cada TypeConverter implementação pode ter sua própria interpretação do que constitui uma cadeia de caracteres válida para uma conversão e também pode usar ou ignorar os contextos de descrição de tipo ou cultura passados como parâmetros. No entanto, o processamento XAML do WPF pode não passar valores para o contexto de descrição do tipo em todos os casos e também pode não passar a cultura com base em xml:lang
.
Nota
Não use os caracteres de chaves, particularmente {, como um possível elemento do formato de cadeia de caracteres. Esses caracteres são reservados como entrada e saída de uma sequência de extensão de marcação.
Implementando ConvertTo
ConvertTo é potencialmente usado para suporte à serialização. O suporte à serialização por meio de ConvertTo para seu tipo personalizado e seu conversor de tipo não é um requisito absoluto. No entanto, se você estiver implementando um controle ou usando a serialização como parte dos recursos ou design de sua classe, deverá implementar ConvertTo.
Para ser utilizável como uma implementação TypeConverter que dá suporte a XAML, o método ConvertTo para esse conversor deve aceitar uma instância do tipo (ou um valor) com suporte como o parâmetro value
. Quando o parâmetro destinationType
é o tipo String, o objeto retornado deve ser capaz de ser convertido como String. A cadeia de caracteres retornada deve representar um valor serializado de value
. O ideal é que o formato de serialização escolhido seja capaz de gerar o mesmo valor se essa cadeia de caracteres tiver sido passada para a implementação ConvertFrom do mesmo conversor, sem perda significativa de informações.
Se o valor não puder ser serializado ou o conversor não der suporte à serialização, a implementação do ConvertTo deverá retornar null
e poderá gerar uma exceção nesse caso. Mas, se você lançar exceções, deverá relatar a incapacidade de usar essa conversão como parte da implementação do CanConvertTo, para que a prática recomendada de primeiro verificar com CanConvertTo para evitar o lançamento de exceções seja viabilizada.
Se o parâmetro destinationType
não for do tipo String, você poderá escolher seu próprio tratamento do conversor. Normalmente, você retornaria ao tratamento da implementação base, que no nível mais básico ConvertTo gera uma exceção específica.
Implementando CanConvertTo
Sua implementação de CanConvertTo deve retornar true
para destinationType
do tipo Stringe, caso contrário, repassar para a implementação base.
Implementando CanConvertFrom
Sua implementação de CanConvertFrom deve retornar true
para sourceType
do tipo Stringe, caso contrário, remeter à implementação base.
Aplicando o Atributo TypeConverter
Para que o conversor de tipo personalizado seja usado como conversor de tipo de ação para uma classe personalizada por um processador XAML, você deve aplicar o TypeConverterAttribute à sua definição de classe. O ConverterTypeName que você especificar por meio do atributo deve ser o nome do tipo do conversor de tipo personalizado. Com esse atributo aplicado, quando um processador XAML manipula valores em que o tipo de propriedade usa seu tipo de classe personalizado, ele pode inserir cadeias de caracteres e retornar instâncias de objeto.
Você também pode fornecer um conversor de tipo por propriedade. Em vez de aplicar um TypeConverterAttribute à definição de classe, aplique-o a uma definição de propriedade (a definição principal, não as implementações de get
/set
dentro dela). O tipo da propriedade deve corresponder ao tipo processado pelo conversor de tipo personalizado. Com esse atributo aplicado, quando um processador XAML manipula valores dessa propriedade, ele pode processar cadeias de caracteres de entrada e retornar instâncias de objeto. A técnica de conversor de tipo por cada propriedade é particularmente útil se você optar por usar um tipo de propriedade do Microsoft .NET Framework ou de alguma outra biblioteca na qual você não tenha controle sobre a definição da classe e não possa aplicar um TypeConverterAttribute lá.
Consulte também
- TypeConverter
- XAML no WPF
- Extensões de marcação e XAML do WPF
- Sintaxe XAML em Detalhe
.NET Desktop feedback