Partilhar via


Definir tipos personalizados para uso com os Serviços XAML do .NET

Quando você define tipos personalizados que são objetos de negócios ou são tipos que não dependem de estruturas específicas, há certas práticas recomendadas para XAML que você pode seguir. Se você seguir essas práticas, os Serviços XAML .NET e seus leitores e gravadores XAML poderão descobrir as características XAML do seu tipo e dar-lhe representação apropriada em um fluxo de nó XAML usando o sistema de tipo XAML. Este tópico descreve as práticas recomendadas para definições de tipo, definições de membro e atribuição CLR de tipos ou membros.

Padrões de construtor e definições de tipo para XAML

Para ser instanciada como um elemento object em XAML, uma classe personalizada deve atender aos seguintes requisitos:

  • A classe personalizada deve ser pública e deve expor um construtor público sem parâmetros. (Consulte a secção seguinte para obter notas sobre estruturas.)

  • A classe personalizada não deve ser uma classe aninhada. O "ponto" extra no caminho de nome completo torna a divisão class-namespace ambígua e interfere com outros recursos XAML, como propriedades anexadas. Se um objeto pode ser instanciado como um elemento de objeto, o objeto criado pode preencher a forma de elemento de propriedade de quaisquer propriedades que tomam o objeto como seu tipo subjacente.

Você ainda pode fornecer valores de objeto para tipos que não atendem a esses critérios, se habilitar um conversor de valor. Para obter mais informações, consulte Conversores de tipo e extensões de marcação para XAML.

Estruturas

As estruturas sempre podem ser construídas em XAML, por definição CLR. Isso ocorre porque um compilador CLR cria implicitamente um construtor sem parâmetros para uma estrutura. Este construtor inicializa todos os valores de propriedade para seus padrões.

Em alguns casos, o comportamento de construção padrão para uma estrutura não é desejável. Isso pode ser porque a estrutura se destina a preencher valores e funcionar conceitualmente como uma união. Como uma união, os valores contidos podem ter interpretações mutuamente exclusivas e, portanto, nenhuma de suas propriedades é configurável. Um exemplo de tal estrutura no vocabulário do WPF é GridLength. Tais estruturas devem implementar um conversor de tipo para que os valores possam ser expressos em forma de atributo, usando convenções de cadeia de caracteres que criam as diferentes interpretações ou modos dos valores da estrutura. A estrutura também deve expor um comportamento semelhante para a construção de código por meio de um construtor sem parâmetros.

Interfaces

As interfaces podem ser usadas como tipos subjacentes de membros. O sistema de tipo XAML verifica a lista atribuível e espera que o objeto fornecido como o valor possa ser atribuído à interface. Não há nenhum conceito de como a interface deve ser apresentada como um tipo XAML, desde que um tipo atribuível relevante ofereça suporte aos requisitos de construção XAML.

Métodos de Fábrica

Os métodos de fábrica são um recurso XAML 2009. Eles modificam o princípio XAML de que os objetos devem ter construtores sem parâmetros. Os métodos de fábrica não estão documentados neste artigo. Consulte x:FactoryMethod Directive.

Enumerações

As enumerações têm comportamento de conversão de tipo nativo XAML. Os nomes de constantes de enumeração especificados em XAML são resolvidos em relação ao tipo de enumeração subjacente e retornam o valor de enumeração para um gravador de objeto XAML.

O XAML oferece suporte a um uso no estilo de sinalizadores para enumerações com FlagsAttribute aplicadas. Para obter mais informações, consulte Sintaxe XAML em detalhes. (Sintaxe XAML em detalhes é escrito para o público WPF, mas a maioria das informações nesse tópico é relevante para XAML que não é específico para uma estrutura de implementação específica.)

Definições de membros

Os tipos podem definir membros para uso de XAML. É possível que os tipos definam membros que são utilizáveis por XAML, mesmo que esse tipo específico não seja utilizável por XAML. Isso é possível devido à herança CLR. Contanto que algum tipo que herde o membro ofereça suporte ao uso de XAML como um tipo, e o membro ofereça suporte ao uso de XAML para seu tipo subjacente ou tenha uma sintaxe XAML nativa disponível, esse membro será utilizável por XAML.

Propriedades

Se você definir propriedades como uma propriedade CLR pública usando o get CLR típico e padrões de acessador set e palavras-chave apropriadas ao idioma, o sistema de tipo XAML poderá relatar a propriedade como um membro com informações apropriadas fornecidas para XamlMember propriedades, como IsReadPublic e IsWritePublic.

Propriedades específicas podem habilitar uma sintaxe de texto aplicando TypeConverterAttribute. Para obter mais informações, consulte Conversores de tipo e extensões de marcação para XAML.

Na ausência de uma sintaxe de texto ou conversão XAML nativa e na ausência de indirecionamento adicional, como um uso de extensão de marcação, o tipo de uma propriedade (TargetType no sistema de tipos XAML) deve ser capaz de retornar uma instância para um gravador de objeto XAML tratando o tipo de destino como um tipo CLR.

Se estiver usando XAML 2009, x:Reference Markup Extension poderá ser usado para fornecer valores se as considerações anteriores não forem atendidas; no entanto, isso é mais um problema de uso do que um problema de definição de tipo.

Publicações

Se você definir eventos como um evento CLR público, o sistema de tipo XAML poderá relatar o evento como um membro com IsEvent como true. A fiação dos manipuladores de eventos não está dentro do escopo dos recursos dos Serviços XAML do .NET; A fiação é deixada para estruturas e implementações específicas.

Metodologia

O código embutido para métodos não é um recurso XAML padrão. Na maioria dos casos, você não faz referência direta a membros do método XAML, e a função dos métodos em XAML é apenas fornecer suporte para padrões XAML específicos. Diretiva x:FactoryMethod é uma exceção.

Campos

As diretrizes de design CLR desencorajam campos não estáticos. Para campos estáticos, você pode acessar valores de campo estático somente por meio de x:Static Markup Extension; neste caso, você não está fazendo nada de especial na definição CLR para expor um campo para usos de x:Static .

Membros amovíveis

Membros anexáveis são expostos a XAML por meio de um padrão de método de acessador em um tipo definidor. O tipo de definição em si não precisa ser utilizável por XAML como um objeto. Na verdade, um padrão comum é declarar uma classe de serviço cuja função é possuir o membro anexável e implementar os comportamentos relacionados, mas não servir nenhuma outra função, como uma representação de interface do usuário. Para as seções a seguir, o espaço reservado PropertyName representa o nome do seu membro anexável. Esse nome deve ser válido no XamlName Grammar.

Tenha cuidado com colisões de nomes entre esses padrões e outros métodos de um tipo. Se existir um membro que corresponda a um dos padrões, ele pode ser interpretado como um caminho de uso de membro anexável por um processador XAML, mesmo que essa não seja sua intenção.

O acessador GetPropertyName

A assinatura do acessador de GetPropertyName deve ser:

public static object GetPropertyName(object target)

  • O objeto target pode ser especificado como um tipo mais específico em sua implementação. Você pode usar isso para definir o escopo do uso de seu membro anexável; usos fora do escopo pretendido lançarão exceções de conversão inválidas que serão exibidas por um erro de análise XAML. O nome do parâmetro target não é um requisito, mas é nomeado target por convenção na maioria das implementações.

  • O valor de retorno pode ser especificado como um tipo mais específico em sua implementação.

Para oferecer suporte a uma sintaxe de texto habilitada para TypeConverter para uso de atributos do membro anexável, aplique TypeConverterAttribute ao acessador GetPropertyName. Aplicar ao get em vez do set pode parecer pouco intuitivo; No entanto, essa convenção pode oferecer suporte ao conceito de membros anexáveis somente leitura que são serializáveis, o que é útil em cenários de designer.

O acessador SetPropertyName

A assinatura do acessador de SetPropertyName deve ser:

public static void SetPropertyName(object target, object value)

  • O objeto target pode ser especificado como um tipo mais específico em sua implementação, com a mesma lógica e consequências descritas na seção anterior.

  • O objeto value pode ser especificado como um tipo mais específico em sua implementação.

Lembre-se de que o valor para esse método é a entrada proveniente do uso de XAML, normalmente na forma de atributo. A partir do formulário de atributo, deve haver suporte ao conversor de valor para uma sintaxe de texto e você atribui no acessador do GetPropertyName.

Lojas de Membros Amovíveis

Os métodos de acesso normalmente não são suficientes para fornecer um meio de colocar valores de membro anexáveis em um gráfico de objeto, ou para recuperar valores fora do gráfico de objeto e serializá-los corretamente. Para fornecer essa funcionalidade, os objetos target nas assinaturas de acessador anteriores devem ser capazes de armazenar valores. O mecanismo de armazenamento deve ser coerente com o princípio do membro anexável de que o membro é anexável a alvos em que o membro anexável não consta da lista de membros. Os Serviços XAML .NET fornecem uma técnica de implementação para repositórios de membros anexáveis por meio das APIs IAttachedPropertyStore e AttachablePropertyServices. IAttachedPropertyStore é usado pelos gravadores XAML para descobrir a implementação do repositório e deve ser implementado no tipo que é o target dos acessadores. As APIs de AttachablePropertyServices estáticas são usadas dentro do corpo dos acessadores e se referem ao membro anexável por seu AttachableMemberIdentifier.

Atribuir corretamente seus tipos, membros e assemblies é importante para relatar informações do sistema de tipo XAML aos Serviços XAML do .NET. Relatar informações de sistema do tipo XAML é relevante se uma das seguintes situações se aplicar:

  • Você pretende que seus tipos sejam usados com sistemas XAML que são diretamente baseados em leitores e gravadores XAML dos Serviços XAML .NET.
  • Você define ou usa uma estrutura que utiliza XAML baseada nesses leitores e gravadores XAML.

Para obter uma lista de cada atributo relacionado a XAML relevante para o suporte a XAML de seus tipos personalizados, consulte XAML-Related Atributos CLR para tipos e bibliotecas personalizados.

Utilização

O uso de tipos personalizados requer que o autor da marcação mapeie um prefixo para o assembly e o namespace CLR que contêm o tipo personalizado. Este procedimento não está documentado neste tópico.

Nível de Acesso

O XAML fornece um meio de carregar e instanciar tipos que têm um nível de acesso internal. Esse recurso é fornecido para que o código do usuário possa definir seus próprios tipos e, em seguida, instanciar essas classes da marcação que também faz parte do mesmo escopo de código do usuário.

Um exemplo do WPF é sempre que o código do usuário define um UserControl que se destina a refatorar um comportamento da interface do usuário, mas não como parte de qualquer mecanismo de extensão possível que possa estar implícito declarando a classe de suporte com public nível de acesso. Esse UserControl pode ser declarado com acesso internal se o código de suporte for compilado no mesmo assembly do qual ele é referenciado como um tipo XAML.

Para um aplicativo que carrega XAML sob confiança total e usa XamlObjectWriter, carregar classes com internal nível de acesso está sempre habilitado.

Para um aplicativo que carrega XAML sob confiança parcial, você pode controlar as características de nível de acesso usando a API XamlAccessLevel. Além disso, os mecanismos de adiamento (como o sistema de modelo WPF) devem ser capazes de propagar quaisquer permissões de nível de acesso e preservá-las para as eventuais avaliações de tempo de execução; Isso é tratado internamente passando as informações XamlAccessLevel.

Implementação do WPF

O WPF XAML usa um modelo de acesso de confiança parcial em que, se o BAML for carregado sob confiança parcial, o acesso será restrito a AssemblyAccessTo para o assembly que é a fonte BAML. Para diferimento, o WPF usa IXamlObjectWriterFactory.GetParentSettings como um mecanismo para passar as informações de nível de acesso.

Na terminologia WPF XAML, um de tipo interno é um tipo definido pelo mesmo assembly que também inclui o XAML de referência. Esse tipo pode ser mapeado por meio de um namespace XAML que deliberadamente omite a parte assembly= de um mapeamento, por exemplo, xmlns:local="clr-namespace:WPFApplication1". Se BAML faz referência a um tipo interno e esse tipo tem internal nível de acesso, isso gera uma classe GeneratedInternalTypeHelper para o assembly. Se quiser evitar GeneratedInternalTypeHelper, você deve usar public nível de acesso ou deve fatorar a classe relevante em um assembly separado e torná-lo dependente.

Ver também