DevsDicas

[Desenvolvimento] LongListSelector: Criando uma lista agrupada por letras

Olá pessoal, tudo bom?

Neste post explico como criar uma lista de carros, por exemplo, agrupada por letras usando o componente LongListSelector do XAML. O trabalho é um pouco árduo, mas vou tentar simplificar as coisas. Vamos a elas:

list-by-letter-longlistselector

1º passo: Criar uma classe em seu projeto para fazer a ordenação e agrupamento dos itens (AlphaKeyGroup.cs)

Essa classe chama-se AlphaKeyGroup<T> e representa a letra do alfabeto e todos os itens que iniciam com ela. Essa classe não é parte do SDK do Windows Phone, por isso, teremos que digitá-la e manualmente adiciona-la ao nosso projeto. Para facilitar, faça o download da classe aqui.

using Microsoft.Phone.Globalization;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ListByLetter
{
  public class AlphaKeyGroup : List
  {
    /// 
    /// O delegate que é usado para obter a informação da chave
    /// 
    /// Um objeto do tipo T
    /// O valor da chave usado para esse objeto
    public delegate string GetKeyDelegate(T item);

    /// 
    /// A chave deste grupo
    /// 
    public string Key { get; private set; }

    /// 
    /// Construtor público
    /// 
    /// 
    public AlphaKeyGroup(string key)
    {
      Key = key;
    }

    /// 
    /// Cria uma lista de AlphaKeyGroup com chaves "setadas" por um SortedLocaleGrouping
    /// 
    /// 
    /// Fonte de dados para o LongListSelector
    private static List> CreateGroups(SortedLocaleGrouping slg)
    {
      List> list = new List>();

      foreach(string key in slg.GroupDisplayNames)
      {
        list.Add(new AlphaKeyGroup(key));
      }

      return list;
    }

    /// 
    /// Cria uma lista de AlphaGroup com as chaves "setadas" por um SortedLocaleGrouping
    /// 
    /// Os itens a serem colocados em grupo
    /// A CultureInfo para ordenar e agrupar
    /// Um delegate para pegar a chave de um item
    /// Irá ordenar os dados se for "true"
    /// Uma fonte de dados para o LongListSelector
    public static List> CreateGroups(IEnumerable items, CultureInfo ci, GetKeyDelegate getKey, bool sort)
    {
      SortedLocaleGrouping slg = new SortedLocaleGrouping(ci);
      List> list = CreateGroups(slg);

      foreach (T item in items)
      {
        int index = 0;
        if (slg.SupportsPhonetics)
        {
          //index = slg.GetGroupIndex(getKey(Yomiof(item)));
        }
        else
        {
          index = slg.GetGroupIndex(getKey(item));
        }
        if (index >= 0 && index < list.Count)
        {
          list[index].Add(item);
        }
      }
      if (sort)
      {
        foreach(AlphaKeyGroup group in list)
        {
          group.Sort((c0, c1) => { return ci.CompareInfo.Compare(getKey(c0), getKey(c1)); });
        }
      }
      return list;
    }
  }
}

2º passo: Preparar a classe que representará os dados para teste

Nesse passo declaramos uma classe Car para posteriormente representarmos uma lista de carros a serem exibidos através do LongListSelector. Vejamos a classe Car.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ListByLetter
{
  public class Car
  {
    public string Name { get; set; }
    public int Year { get; set; }
    public string Brand { get; set; }
  }
}

Agora, para popular nossa lista de carros vamos utilizar o próprio construtor da MainPage.xaml.cs. Veja o código abaixo:

public MainPage()
{
  InitializeComponent();

  this.Loaded += MainPage_Loaded;
}

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
  List cars = new List();
  cars.Add(new Car { Name = "Fusca", Year = 1972, Brand = "VW" });
  cars.Add(new Car { Name = "Frontier", Year = 2009, Brand = "Nissan" });
  cars.Add(new Car { Name = "C3", Year = 2012, Brand = "Citroen" });
  cars.Add(new Car { Name = "Corolla", Year = 2009, Brand = "Toyota" });
  cars.Add(new Car { Name = "Uno", Year = 2002, Brand = "Fiat" });
  cars.Add(new Car { Name = "Ford Modelo A", Year = 1929, Brand = "Ford" });
  cars.Add(new Car { Name = "Fusca", Year = 1982, Brand = "VW" });
  cars.Add(new Car { Name = "Symbol", Year = 2009, Brand = "Renault" });
  cars.Add(new Car { Name = "Palio", Year = 2007, Brand = "Fiat" });
  cars.Add(new Car { Name = "Civic", Year = 2007, Brand = "Honda" });
  cars.Add(new Car { Name = "Camaro", Year = 2014, Brand = "Chevrolet" });
  cars.Add(new Car { Name = "Monza", Year = 1985, Brand = "Chevrolet" });

  List> list = AlphaKeyGroup.CreateGroups(cars, Thread.CurrentThread.CurrentUICulture, c => c.Brand, true);

  llsCars.ItemsSource = list; //Ver comentário abaixo
}

O objeto llsCars corresponde ao LongListSelector que será declarado mais à frente…

3° passo: Definição do LongListSelector e seus respectivos recursos – XAML

Em relação ao desenvolvimento XAML temos que declarar o LongListSelector e mais alguns Resources para a página onde o mesmo será exibido, em nosso caso, na própria MainPage.xaml.

Teremos que definir um DataTemplate para quando a lista agrupada por letras estiver em modo de exibição de seus itens e um estilo para quando o LongListSelector estiver em modo de seleção de suas opções. Devemos reparar que na definição do estilo estaremos usando dois converters chamados de JumpListItemBackgroundConverter e JumpListItemForegroundConverter, sendo que os mesmos são usados para identificar os grupos de letras que não possuem itens, ou seja, devem aparecer em cinza para que o usuário já perceba que ali não há itens a serem exibidos. Caso contrário, os grupos de letras serão exibidos em branco com o fundo de acordo com o phone accent color.

Ainda em relação aos recursos da página, teremos outro DataTemplate que irá dizer para para o LongListSelector a forma como os dados dos carros deverão ser apresentados. Vamos às definições:

...


  
  
    
      
        
      
    
  

  
  
  

  
  

  
  
    
      
      
      
    
  

...

Por fim, devemos agora declarar o próprio LongListSelector e indicar a ele todos os recursos a serem utilizados. Vejamos:

...

  

...

Agora basta executar e visualizar o resultado. Fácil, não? 🙂

Grande abraço !
Eduardo Henrique Rizo (@eduardorizo)

Post Relacionado: 

Fonte: Blog do Eduardo H. Rizo