Seleção de modelo de dados: Estilizando itens com base em suas propriedades

O design personalizado dos controles de coleções é gerenciado por um DataTemplate. Os modelos de dados definem como cada item deve ser definido e estilizado, e essa marcação é aplicada a cada item da coleção. Este artigo explica como usar um DataTemplateSelector para aplicar modelos de dados diferentes em uma coleção e selecionar qual modelo de dados usar, com base em determinadas propriedades de item ou valores de sua escolha.

APIs importantes: DataTemplateSelector, DataTemplate

DataTemplateSelector é uma classe que habilita a lógica de seleção de modelo personalizada. Ele permite definir regras que especificam qual modelo de dados usar para determinados itens em uma coleção. Para implementar essa lógica, você cria uma subclasse de DataTemplateSelector em seu code-behind e define a lógica que determina qual modelo de dados usar para qual categoria de itens (por exemplo, itens de um determinado tipo ou itens com um determinado valor de propriedade, etc. Você declara uma instância dessa classe na seção Recursos do arquivo XAML, juntamente com as definições dos modelos de dados que você usará. Você identifica esses recursos com um x:Key valor, o que permite referenciá-los em seu XAML.

Pré-requisitos

Quando não usar um DataTemplateSelector

Em geral, você não deve dar a cada item em um ListView ou GridView um layout/estilo completamente diferente - isso seria um mau uso de um DataTemplateSelector e afetará negativamente o desempenho.

Determinados elementos da exibição visual de um item de lista podem ser controlados usando apenas um modelo de dados, por meio da associação de determinadas propriedades. Por exemplo, cada um dos itens pode ter um ícone diferente associando-se a uma propriedade de origem de ícone no modelo de dados e dando a cada item um valor diferente para essa propriedade de origem do ícone. Isso alcançaria um desempenho melhor do que usar um DataTemplateSelector.

Quando usar um DataTemplateSelector

Você deve criar um DataTemplateSelector quando quiser usar vários modelos de dados em um controle de coleção. A DataTemplateSelector oferece a flexibilidade para destacar determinados itens, mantendo os itens em um layout semelhante. Há muitos casos de uso em que um DataTemplateSelector é útil e alguns cenários em que é melhor pensar novamente o controle e a estratégia que você está usando.

Normalmente, os controles de coleção são associados a uma coleção de itens que são todos de um tipo. No entanto, mesmo que os itens possam ser do mesmo tipo, eles podem ter valores diferentes para determinadas propriedades ou representar significados diferentes. Determinados itens também podem ser mais importantes do que outros, ou um item pode ser particularmente importante ou diferente e precisa se destacar visualmente. Nessas situações, um DataTemplateSelector será muito útil.

Também é possível associar a uma coleção que contém diferentes tipos de itens – a coleção associada pode ter uma mistura de cadeias de caracteres, ints, objetos de classe personalizada e muito mais. Isso torna o DataTemplateSelector especialmente útil, pois pode atribuir modelos de dados diferentes com base no tipo de objeto de um item.

Aqui estão alguns exemplos de quando você pode usar um seletor de modelo de dados:

  • Representando diferentes níveis de funcionários em um ListView - cada tipo/nível de funcionário pode precisar de um plano de fundo de cor diferente para ser facilmente distinguível.
  • Representando itens de venda em uma galeria de produtos que usa um GridView - um item de venda pode precisar de um plano de fundo vermelho ou uma fonte de cor diferente para fazer com que ele se destaque dos itens com preços regulares.
  • Representando fotos vencedoras/principais na galeria de fotos usando FlipView.
  • Precisando representar números negativos/positivos em um ListView de forma diferente ou cadeias de caracteres curtas/cadeias de caracteres longas.

Criar um DataTemplateSelector

Ao criar um seletor de modelo de dados, você define a lógica de seleção de modelo em seu código e define os modelos de dados em seu XAML.

Componente code-behind

Para usar um seletor de modelo de dados, primeiro você cria uma subclasse de DataTemplateSelector (uma classe que deriva dele) em seu code-behind. Em sua classe, você declara cada modelo como uma propriedade da classe. Em seguida, você substitui o método SelectTemplateCore para incluir sua própria lógica de seleção de modelo.

Aqui está um exemplo de uma subclasse simples DataTemplateSelector chamada MyDataTemplateSelector.

public class MyDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate Normal { get; set; }
    public DataTemplate Accent { get; set; }

    protected override DataTemplate SelectTemplateCore(object item)
    {
        if ((int)item % 2 == 0)
        {
            return Normal;
        }
        else
        {
            return Accent;
        }
    }
}

A MyDataTemplateSelector classe deriva da DataTemplateSelector classe e primeiro define dois objetos DataTemplate : Normal e Accent. Estas são declarações vazias por enquanto, mas serão "preenchidas" com marcação no arquivo XAML.

O método SelectTemplateCore usa um objeto de item (ou seja, cada item da coleção) e é substituído por regras que especificam em que circunstâncias cada DataTemplate deve ser retornado. Nesse caso, se o item for um número ímpar, ele receberá o Accent modelo de dados, enquanto se for um número par, ele receberá o Normal modelo de dados.

Componente XAML

Em segundo lugar, você deve criar uma instância dessa nova MyDataTemplateSelector classe na seção Recursos do arquivo XAML. Todos os recursos exigem um x:Key, sendo usado para associá-lo à propriedade ItemTemplateSelector do controle de coleção (em uma etapa posterior). Você também cria duas instâncias de DataTemplate objetos e define seu layout na seção de recursos. Você atribui esses modelos de dados às propriedades Accent e Normal que você declarou na classe MyDataTemplateSelector.

Aqui está um exemplo dos recursos XAML e marcação necessários:

<Page.Resources>

<DataTemplate x:Key="NormalItemTemplate" x:DataType="x:Int32">
    <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{ThemeResource SystemChromeLowColor}">
        <TextBlock Text="{x:Bind}" />
    </Button>
</DataTemplate>

<DataTemplate x:Key="AccentItemTemplate" x:DataType="x:Int32">
    <Button HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="{ThemeResource SystemAccentColor}">
        <TextBlock Text="{x:Bind}" />
    </Button>
</DataTemplate>

<l:MyDataTemplateSelector x:Key="MyDataTemplateSelector"
    Normal="{StaticResource NormalItemTemplate}"
    Accent="{StaticResource AccentItemTemplate}"/>

</Page.Resources>

Como você pode ver acima, os dois modelos de dados Normal e Accent são definidos – ambos exibem itens como botões, no entanto, o modelo de dados Accent usa um pincel de cor de ênfase para o fundo, enquanto o modelo de dados Normal usa um pincel de cor cinza SystemChromeLowColor. Esses dois modelos de dados são atribuídos aos objetos DataTemplate Normal e Accent, que são atributos da classe MyDataTemplateSelector, criada no code-behind do C#.

A última etapa é vincular o seu DataTemplateSelector à propriedade ItemTemplateSelector do controle de coleções (por exemplo, um ListView). Isso substitui a necessidade de atribuir um valor à ItemTemplate propriedade.

<ListView x:Name = "TestListView"
          ItemsSource = "{x:Bind NumbersList}"
          ItemTemplateSelector = "{StaticResource MyDataTemplateSelector}">
</ListView>

Depois que o código for compilado, cada item da coleção será executado por meio do método SelectTemplateCore substituído em MyDataTemplateSelector e será renderizado com o DataTemplate apropriado.

Importante

Ao usar DataTemplateSelector com um ItemsRepeater, você associa DataTemplateSelector à propriedade ItemTemplate. ItemsRepeater não tem uma propriedade ItemTemplateSelector.

Considerações sobre o desempenho de DataTemplateSelector

Quando você usa um ListView ou GridView com uma grande coleção de dados, o desempenho de rolagem e navegação pode ser uma preocupação. Para manter as grandes coleções com bom desempenho, há algumas etapas que você pode executar para melhorar o desempenho dos modelos de dados. Elas são descritas com mais detalhes na otimização da Interface do Usuário de ListView e GridView.

  • Redução de elemento por item – mantenha o número de elementos de interface do usuário em um modelo de dados no mínimo razoável.
  • Reciclagem de contêiner com coleções heterogêneas
    • Usar o evento ChoosingItemContainer – Este evento é a maneira mais eficaz de usar diferentes modelos de dados para itens diversificados. Para obter o melhor desempenho, você deve otimizar o cache e selecionar modelos de dados para seus dados específicos.
    • Use um seletor de modelo de item – Deve-se evitar um seletor de modelo de item (DataTemplateSelector) em alguns casos devido ao seu impacto no desempenho.