TypeConverters e XAML

Este tópico apresenta a finalidade da conversão de tipo de cadeia de caracteres como um recurso de linguagem XAML geral. No .NET Framework, a classe serve a TypeConverter 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 as instâncias de sua classe sejam utilizáveis como valores de atributo configuráveis XAML, talvez seja necessário aplicar um TypeConverterAttribute à sua classe, escrever uma classe personalizada TypeConverter ou ambos.

Conceitos de conversão de tipos

XAML e valores de cadeia de caracteres

Quando um valor de atributo é definido em um arquivo XAML, o tipo inicial desse valor é uma cadeia de caracteres em texto simples. Mesmo outras primitivas, 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 informação é o tipo de valor da propriedade que está sendo definido. Qualquer cadeia de caracteres que define um valor de atributo e que é processada em XAML deve, por fim, ser convertida ou resolvida para um valor desse tipo. Caso o valor seja um primitivo compreendido pelo analisador XAML (como um valor numérico), será tentada uma conversão direta da cadeia de caracteres. Se o valor for uma enumeração, a cadeia de caracteres será usada para verificar se há uma correspondência de nome com uma constante nomeada na 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 por meio de indicação de uma classe de conversor de tipos. O conversor de tipos é uma classe auxiliar para fornecer valores de outra classe, tanto para o cenário XAML quanto, potencialmente, para chamadas de código no código .NET.

Usando o comportamento de conversão de tipo existente em XAML

Dependendo da sua familiaridade com os conceitos fundamentais de XAML, você pode já estar usando o comportamento de conversão de tipos no aplicativo básico XAML sem perceber. Por exemplo, o WPF define literalmente centenas de propriedades que têm um valor do tipo Point. A Point é um valor que descreve uma coordenada em um espaço de coordenadas bidimensional, e ele realmente só tem duas propriedades importantes: X e Y. Ao especificar um ponto em XAML, você o especifica como uma cadeia de caracteres com um delimitador (normalmente uma vírgula) entre os X valores e Y fornecidos. Por exemplo: <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"/>.

Mesmo esse tipo simples de e seu uso simples em XAML envolvem um conversor de Point tipo. Neste caso, essa é a classe PointConverter.

O conversor de tipo para Point definido no nível de classe simplifica os usos de marcação de todas as propriedades que usam Pointo . Sem um conversor de tipos aqui, você precisaria da marcação muito mais detalhada a seguir 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 cadeia de caracteres de conversão de tipo ou uma sintaxe equivalente mais detalhada geralmente é uma opção de estilo de codificação. O fluxo de trabalho das ferramentas XAML também pode influenciar a forma como os valores são definidos. Algumas ferramentas XAML tendem a emitir a forma mais detalhada da marcação, porque é mais fácil ir e voltar de modos de exibição de designer ou do próprio mecanismo de serialização.

Os conversores de tipo existentes geralmente podem ser descobertos em tipos WPF e .NET Framework verificando uma classe (ou propriedade) para a presença de um TypeConverterAttributearquivo . Esse atributo nomeará a classe que é o conversor de tipos de suporte para valores desse tipo, para fins de XAML e, potencialmente, outras finalidades.

Conversores de tipo e extensões de marcação

As extensões de marcação e os conversores de tipos exercem 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 tipos de propriedades em que uma extensão de marcação fornece um valor geralmente não é verificado em implementações de extensão de marcação. Em outras palavras, mesmo se uma extensão de marcação retornar uma cadeia de caracteres de texto como saída do ProvideValue, o comportamento de conversão de tipo dessa cadeia de caracteres, conforme aplicado a uma propriedade específica ou a um tipo de valor da propriedade, não será chamado. Em geral, a finalidade de uma extensão de marcação é processar uma cadeia de caracteres e retornar um objeto sem nenhum conversor de tipo envolvido.

Uma situação comum em que uma extensão de marcação é necessária, em vez de um conversor de tipos, é para fazer referência a um objeto que já existe. Na melhor das hipóteses, um conversor de tipo sem monitoração de estado pode gerar somente 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 e XAML WPF.

Conversores de tipos nativos

Na implementação do analisador XAML do WPF e do .NET Framework, alguns tipos têm manipulação de conversão de tipos nativos; porém, não são tipos que poderiam ser interpretados, convencionalmente, como primitivos. Um exemplo desse tipo é DateTime. A razão para isso se baseia em como a arquitetura do .NET Framework funciona: o tipo DateTime é definido em mscorlib, a biblioteca mais básica do .NET. DateTime não tem permissão para ser atribuído a um atributo que vem de outro assembly que introduz uma dependência (TypeConverterAttribute é do sistema), portanto, o mecanismo de descoberta de conversor de tipo usual atribuindo não pode ser suportado. Em vez disso, o analisador XAML tem uma lista de tipos que precisam de tal processamento nativo e os processa da mesma forma como os primitivos verdadeiros são processados. (No caso disso DateTime , envolve uma chamada para Parse.)

Implementando um conversor de tipos

TypeConverter

Point No exemplo dado anteriormente, a classe PointConverter foi mencionada. Para implementações .NET de XAML, todos os conversores de tipo usados para fins XAML são classes derivadas da classe TypeConverterbase . A TypeConverter classe 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 é expandida para incluir ser a classe base para conversões de cadeia de caracteres e de cadeia de caracteres que permitem analisar um valor de atributo de cadeia de caracteres e, possivelmente, processar um valor de tempo de execução de uma propriedade de objeto específica de volta em uma cadeia de TypeConverter caracteres para serialização como um atributo.

TypeConverter define quatro membros que são 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 para o tipo de objeto necessário. Estritamente falando, o método poderia ser implementado para converter uma gama muito maior de tipos no tipo de destino pretendido do conversor e, portanto, servir a propósitos que vão além do XAML, como dar suporte a conversões em tempo de execução, mas para fins de XAML é apenas o ConvertFrom caminho de código que pode processar uma String entrada que importa.

O próximo método mais importante é ConvertToo . Se um aplicativo for convertido em uma representação de marcação (por exemplo, se 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 importante para XAML é quando você passa um destinationType de String .

CanConvertTo e CanConvertFrom são métodos de suporte usados quando um serviço consulta os recursos da TypeConverter implementação. Esses métodos devem ser implementados para retornar o true para casos específicos de tipo aos quais os métodos de conversão equivalentes do seu conversor dão suporte. Para fins XAML, isso geralmente significa o String tipo.

Informações de cultura e conversores de tipos 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. Há uma consideração importante em relação à cultura e à conversão de tipos XAML. O XAML dá suporte total ao uso de cadeias de caracteres localizáveis como valores de atributos. Porém, não há suporte para o uso dessa cadeia de caracteres localizável como entrada do conversor de tipos com exigências específicas de cultura, porque os conversores de tipos para valores de atributos XAML envolvem um comportamento de análise de linguagem necessariamente fixo, usando a cultura do en-US. Para obter mais informações sobre os motivos de design para essa restrição, consulte a especificação de linguagem XAML ([MS-XAML].

Como exemplo de casos em que a cultura pode ser um problema, algumas culturas usam vírgula como delimitador de ponto decimal para números. Isso vai de encontro ao comportamento que muitos dos conversores de tipos XAML do WPF têm, que é usar uma vírgula como delimitador (com base em precedentes históricos, como a forma comum X,Y ou listas delimitadas por vírgulas). Nem mesmo a passagem de uma cultura no XAML ao redor (definindo Language ou xml:lang para a cultura do sl-SI, um exemplo de cultura que usa vírgula para decimal dessa maneira) resolve o problema.

Implementando ConvertFrom

Para ser utilizável como uma implementação que ofereça suporte a XAML, o ConvertFrom método para esse conversor deve aceitar uma TypeConverter cadeia de caracteres como parâmetrovalue. Se a cadeia de caracteres estava em formato válido e pode ser convertida pela implementação, o objeto retornado deve oferecer suporte a uma conversão para o tipo esperado pela TypeConverter propriedade. Caso contrário, a ConvertFrom implementação 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 a descrição do tipo ou contextos de cultura passados como parâmetros. No entanto, o processamento de XAML do WPF não pode passar valores para o contexto de descrição de tipo em todos os casos; tampouco consegue passar a cultura com base no xml:lang.

Observação

Não utilize os caracteres de chave, especialmente o {, como elemento possível do formato da cadeia de caracteres. Esses caracteres são reservados como entrada e saída para uma sequência de extensão de marcação.

Implementando ConvertTo

ConvertTo é potencialmente usado para suporte à serialização. O suporte à serialização para ConvertTo 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 de como parte dos recursos ou design de sua classe, você deve implementar ConvertTo.

Para ser utilizável como uma implementação que ofereça suporte a XAML, o ConvertTo método para esse conversor deve aceitar uma TypeConverter instância do tipo (ou um valor) com suporte como parâmetrovalue. Quando o parâmetro é o destinationType 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. Idealmente, o formato de serialização escolhido deve ser capaz de gerar o mesmo valor se essa cadeia de caracteres fosse passada para a ConvertFrom implementação do mesmo conversor, sem perda significativa de informações.

Se o valor não puder ser serializado ou o conversor não oferecer suporte à serialização, a ConvertTo implementação deverá retornar nulle terá permissão para lançar uma exceção nesse caso. Mas se você lançar exceções, deverá relatar a incapacidade de usar essa conversão como parte de sua CanConvertTo implementação para que a prática recomendada de verificar com CanConvertTo primeiro para evitar exceções seja suportada.

Se destinationType o parâmetro não for do tipo String, você pode escolher seu próprio manuseio do conversor. Normalmente, você reverteria para o tratamento de implementação de base, que na maioria ConvertTo das bases gera uma exceção específica.

Implementando CanConvertTo

Sua CanConvertTo implementação deve retornar true para o tipo Stringe, caso contrário, adiar para destinationType a implementação base.

Implementando CanConvertFrom

Sua CanConvertFrom implementação deve retornar true para o tipo Stringe, caso contrário, adiar para sourceType a implementação base.

Aplicando o TypeConverterAttribute

Para que seu conversor de tipo personalizado seja usado como o conversor de tipo de atuação para uma classe personalizada por um processador XAML, você deve aplicar o à sua definição de TypeConverterAttribute 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 o tipo de classe personalizada, ele pode processar cadeias de caracteres de entrada e retornar as instâncias de objeto.

Também é possível fornecer um conversor de tipos por propriedade. Em vez de aplicar um TypeConverterAttribute à definição de classe, aplique-a a uma definição de propriedade (a definição principal, não as get/set implementações dentro dela). O tipo da propriedade deve corresponder ao tipo que é processado pelo conversor de tipos personalizado. Com esse atributo aplicado, quando um processador XAML manipula valores dessa propriedade, ele pode processar cadeias de caracteres de entrada e instâncias de objeto de retorno. A técnica de conversor de tipo por propriedade é particularmente útil se você optar por usar um tipo de propriedade do Microsoft .NET Framework ou de alguma outra biblioteca em que você não pode controlar a definição de classe e não pode aplicar um TypeConverterAttribute lá.

Confira também