Como agrupar itens em uma lista ou grade

Como agrupar itens em uma lista ou grade (XAML)

[ Este artigo destina-se aos desenvolvedores do Windows 8.x e do Windows Phone 8.x que escrevem aplicativos do Windows Runtime. Se você estiver desenvolvendo para o Windows 10, consulte documentação mais recente ]

Quando um ListView ou um GridView está associado a uma fonte de dados que contém grupos de dados, você pode exibir os dados agrupados na lista ou grade. Há diversas maneiras de agrupar os dados inseridos no seu aplicativo. A fonte de dados pode ser uma lista de itens, em que cada item também inclui uma lista de itens. Por exemplo, você pode exibir uma lista de projetos, em que cada projeto tem uma propriedade que é uma lista de atividades. Se preferir, use uma consulta LINQ que retorne os itens agrupados. Nós vamos ver aqui como exibir esses grupos em uma lista ou grade.

Mapa: Como este tópico está relacionado aos outros? Veja:

O que você precisa saber

Tecnologias

Pré-requisitos

Instruções

Etapa 1: Associar ItemsSource a CollectionViewSource

Para exibir os dados agrupados, defina a propriedade ItemsControl.ItemsSource como CollectionViewSource que tenha sua propriedade IsSourceGrouped definida como true. A CollectionViewSource atua como proxy na classe de coleção para habilitar o suporte a moeda e agrupamento.

Hh780627.wedge(pt-br,WIN.10).gifPara usar uma fonte de dados agrupados

  1. Defina a propriedade ItemsSource da lista ou grade como uma instância de CollectionViewSource.
  2. Defina a propriedade CollectionViewSource.Source como a fonte de dados agrupados.
  3. Defina a propriedade CollectionViewSource.IsSourceGrouped como true.

Aqui, uma coleção de itens Activity foi adicionada à uma lista. Cada itemActivity tem uma propriedade Project que especifica um projeto ao qual a Activity está associada. Uma consulta LINQ é usada para agrupar as atividades por projeto. Os dados agrupados resultantes são definidos como CollectionViewSource.Source. A definição da classe Activity é mostrada mais adiante no exemplo de código completo.


List<Activity> Activities = new List<Activity>();

Activities.Add(new Activity() 
    { Name = "Activity 1", Complete = true, 
        DueDate = startDate.AddDays(4), Project = "Project 1" });
Activities.Add(new Activity() 
    { Name = "Activity 2", Complete = true, 
        DueDate = startDate.AddDays(5), Project = "Project 1" });
Activities.Add(new Activity() 
    { Name = "Activity 3", Complete = false, 
        DueDate = startDate.AddDays(7), Project = "Project 1" });
Activities.Add(new Activity() 
    { Name = "Activity 4", Complete = false, 
        DueDate = startDate.AddDays(9), Project = "Project 1" });
Activities.Add(new Activity() 
    { Name = "Activity 5", Complete = false, 
        DueDate = startDate.AddDays(14), Project = "Project 1" });
Activities.Add(new Activity() 
    { Name = "Activity A", Complete = true, 
        DueDate = startDate.AddDays(2), Project = "Project 2" });
Activities.Add(new Activity() 
    { Name = "Activity B", Complete = false, 
        DueDate = startDate.AddDays(4), Project = "Project 2" });
Activities.Add(new Activity() 
    { Name = "Activity C", Complete = true, 
        DueDate = startDate.AddDays(5), Project = "Project 2" });
Activities.Add(new Activity() 
    { Name = "Activity D", Complete = false, 
        DueDate = startDate.AddDays(9), Project = "Project 2" });
Activities.Add(new Activity() 
    { Name = "Activity E", Complete = false, 
        DueDate = startDate.AddDays(18), Project = "Project 2" });

var result = from act in Activities group act by act.Project into grp orderby grp.Key select grp;
cvsActivities.Source = result;


A CollectionViewSource é declarada em XAML como um recurso da página principal. A propriedade IsSourceGrouped é definida como true. A propriedade ItemsSource do ListView está associada a CollectionViewSource.


<CollectionViewSource x:Name="cvsActivities" IsSourceGrouped="True"/>


Você pode exibir os dados agrupados de uma coleção em que cada item tenha uma lista de itens filho que compõem o grupo. Nesse caso, defina a propriedade CollectionViewSource.ItemsPath para especificar a propriedade do item que contém a coleção de itens filho.

Hh780627.wedge(pt-br,WIN.10).gifPara usar a fonte de dados em que cada item inclui uma coleção de itens filho

  1. Siga as etapas de 1 a 3 descritas anteriormente neste tópico.
  2. Defina a propriedade CollectionViewSource.ItemsPath como a propriedade que contém a coleção de itens filho.

Aqui, você cria a lista de itens Project para exibir em GridView. Os dados são configurados para que cada item Project tenha uma propriedade Activities que seja uma lista de itens Activity. A lista de projetos é definida como CollectionViewSource.Source. As definições das classes Project e Activity são mostradas mais adiante no exemplo de código completo.


List<Project> Projects = new List<Project>();

Project newProject = new Project();
newProject.Name = "Project 1";
newProject.Activities.Add(new Activity() 
    { Name = "Activity 1", Complete = true, DueDate = startDate.AddDays(4) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity 2", Complete = true, DueDate = startDate.AddDays(5) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity 3", Complete = false, DueDate = startDate.AddDays(7) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity 4", Complete = false, DueDate = startDate.AddDays(9) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity 5", Complete = false, DueDate = startDate.AddDays(14) });
Projects.Add(newProject);

newProject = new Project();
newProject.Name = "Project 2";
newProject.Activities.Add(new Activity() 
    { Name = "Activity A", Complete = true, DueDate = startDate.AddDays(2) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity B", Complete = false, DueDate = startDate.AddDays(3) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity C", Complete = true, DueDate = startDate.AddDays(5) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity D", Complete = false, DueDate = startDate.AddDays(9) });
newProject.Activities.Add(new Activity() 
    { Name = "Activity E", Complete = false, DueDate = startDate.AddDays(18) });
Projects.Add(newProject);

newProject = new Project();
newProject.Name = "Project 3";
Projects.Add(newProject);

cvsProjects.Source = Projects;


A CollectionViewSource é declarada em XAML como um recurso da página principal. A propriedade IsSourceGrouped é definida como true, e a propriedade ItemsPath é definida como a propriedade Project.Activities que inclui a coleção de itens Activity. A propriedade ItemsSource do GridView está associada a CollectionViewSource.


<CollectionViewSource x:Name="cvsProjects" IsSourceGrouped="True" ItemsPath="Activities"/>


Para saber mais sobre vinculação e agrupamento de dados, veja Vinculação de dados com XAML.

Etapa 2: Definir um GroupStyle para especificar como os grupos são exibidos

Para exibir os dados agrupados em uma lista ou grade, defina um GroupStyle que especifique um modelo de cabeçalho para cada grupo. Por padrão, o cabeçalho do grupo é exibido para os grupos vazios. Para ocultar o cabeçalho dos grupos vazios, defina a propriedade HidesIfEmpty como true.

Hh780627.wedge(pt-br,WIN.10).gifPara especificar como os grupos são exibidos

  1. Defina um GroupStyle para ListView ou GridView.
  2. No GroupStyle, defina um HeaderTemplate que especifique a aparência dos cabeçalhos de grupo.
  3. Para ocultar os cabeçalhos dos grupos vazios, defina a propriedade GroupStyle.HidesIfEmpty como true.

Aqui, você usa um GridView para exibir a lista de Projects criada anteriormente. A aparência dos itens individuais em cada grupo é definida pelo ItemTemplate, da mesma forma que é definida para os dados que não são agrupados. O ItemsPanel especifica como os grupos são organizados no GridView. A lista de Projects inclui um projeto com uma coleção de Activities vazias. Defina a propriedade HidesIfEmpty como true para ocultar esse grupo vazio.


<GridView ItemsSource="{Binding Source={StaticResource cvsProjects}}" 
  Margin="0,120,0,0" MaxHeight="500" Grid.Column="1">
    <GridView.ItemTemplate>
        <DataTemplate>
            <StackPanel Margin="20">
                <TextBlock Text="{Binding Name}" FontWeight="Bold" 
                           Style="{StaticResource BaseTextBlockStyle}"/>
                <TextBlock Text="{Binding DueDate}" TextWrapping="NoWrap" 
                           Style="{StaticResource BodyTextBlockStyle}" />
                <CheckBox Content="Complete" IsChecked="{Binding Complete}" 
                          IsEnabled="False"/>
            </StackPanel>
        </DataTemplate>
    </GridView.ItemTemplate>
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <ItemsWrapGrid MaximumRowsOrColumns="3"/>
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>

    <GridView.GroupStyle>
        <GroupStyle HidesIfEmpty="True">
            <GroupStyle.HeaderTemplate>
                <DataTemplate>
                    <Grid Background="LightGray" Margin="0">
                        <TextBlock Text='{Binding Name}' 
                                   Foreground="Black" Margin="30"
                                   Style="{StaticResource HeaderTextBlockStyle}"/>
                    </Grid>
                </DataTemplate>
            </GroupStyle.HeaderTemplate>

        </GroupStyle>
    </GridView.GroupStyle>
</GridView>


Etapa 3: Definir GroupStyle usando GroupStyleSelector

Para usar o GroupStyle definido como um recurso ou para aplicar um GroupStyle usando lógica condicional, use um GroupStyleSelector.

Hh780627.wedge(pt-br,WIN.10).gifPara usar um GroupStyleSelector

  1. Crie uma subclasse da classe GroupStyleSelector e substitua o método SelectGroupStyleCore.

    Aqui, você cria uma classe chamada ListGroupStyleSelector que tem origem no GroupStyleSelector. Você substitui o método SelectGroupStyleCore para retornar um recurso GroupStyle que tenha a chave listViewGroupStyle. Esse recurso é declarado no arquivo App.xaml. Você pode aplicar a lógica condicional se tiver que escolher entre estilos de grupo diferentes para retornar.

    
    public class ListGroupStyleSelector : GroupStyleSelector
    {
        protected override GroupStyle SelectGroupStyleCore(object group, uint level)
        {
            return (GroupStyle)App.Current.Resources["listViewGroupStyle"];
        }
    }
    
    
    
  2. Em seu arquivo XAML, defina uma instância da classe do seletor de estilos de grupo.

    Esse recurso é declarado na seção Resources da página.

    
    <local:ListGroupStyleSelector x:Key="listGroupStyleSelector"/>
    
    
    
  3. Defina a propriedade GroupStyleSelector do controle do item para o recurso definido na etapa anterior.

    Aqui, você cria um ListView para exibir a lista de Activities já criada. O ItemTemplate é definido para o recurso com a chave listViewItemTemplate, e a propriedade GroupStyleSelector é definida para o recurso com a chave listGroupStyleSelector. Esses recursos são mostrados mais adiante no exemplo de código completo.

    
    <ListView ItemsSource="{Binding Source={StaticResource cvsActivities}}"
      ItemTemplate="{StaticResource listViewItemTemplate}"
      GroupStyleSelector="{StaticResource listGroupStyleSelector}"
      Margin="120" Width="320"/>
    
    
    

Comentários

Veja a aparência dos modos de exibição de lista e grade quando você executa o aplicativo.

Modo de exibição de lista agrupado

 

Modo de exibição de grade agrupado

Para obter mais exemplos de código que mostram como agrupar e exibir dados, veja estes exemplos:

Exemplo completo

Veja a seguir o código completo dos exemplos usados neste tópico.

MainPage.xaml


<Page
    x:Class="ItemsControlGroupingSnippets.MainPage"
    IsTabStop="false"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ItemsControlGroupingSnippets"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
    <UserControl.Resources>
        <CollectionViewSource x:Name="cvsActivities" IsSourceGrouped="True"/>

        <CollectionViewSource x:Name="cvsProjects" IsSourceGrouped="True" ItemsPath="Activities"/>

        <local:ListGroupStyleSelector x:Key="listGroupStyleSelector"/>
    </UserControl.Resources>

    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="600"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <ListView ItemsSource="{Binding Source={StaticResource cvsActivities}}"
          ItemTemplate="{StaticResource listViewItemTemplate}"
          GroupStyleSelector="{StaticResource listGroupStyleSelector}"
          Margin="120" Width="320"/>

        <GridView ItemsSource="{Binding Source={StaticResource cvsProjects}}" 
          Margin="0,120,0,0" MaxHeight="500" Grid.Column="1">
            <GridView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="20">
                        <TextBlock Text="{Binding Name}" FontWeight="Bold" 
                                   Style="{StaticResource BaseTextBlockStyle}"/>
                        <TextBlock Text="{Binding DueDate}" TextWrapping="NoWrap" 
                                   Style="{StaticResource BodyTextBlockStyle}" />
                        <CheckBox Content="Complete" IsChecked="{Binding Complete}" 
                                  IsEnabled="False"/>
                    </StackPanel>
                </DataTemplate>
            </GridView.ItemTemplate>
            <GridView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsWrapGrid MaximumRowsOrColumns="3"/>
                </ItemsPanelTemplate>
            </GridView.ItemsPanel>

            <GridView.GroupStyle>
                <GroupStyle HidesIfEmpty="True">
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Background="LightGray" Margin="0">
                                <TextBlock Text='{Binding Name}' 
                                           Foreground="Black" Margin="30"
                                           Style="{StaticResource HeaderTextBlockStyle}"/>
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>

                </GroupStyle>
            </GridView.GroupStyle>
        </GridView>
    </Grid>
</Page>


code-behind MainPage.xaml


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

namespace ItemsControlGroupingSnippets
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        DateTime startDate;
        public MainPage()
        {
            this.InitializeComponent();
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            DateTime.TryParse("1/1/2014", out startDate);

            PopulateProjects();
            PopulateActivities();
        }

        private void PopulateActivities()
        {
            List<Activity> Activities = new List<Activity>();

            Activities.Add(new Activity() 
                { Name = "Activity 1", Complete = true, 
                    DueDate = startDate.AddDays(4), Project = "Project 1" });
            Activities.Add(new Activity() 
                { Name = "Activity 2", Complete = true, 
                    DueDate = startDate.AddDays(5), Project = "Project 1" });
            Activities.Add(new Activity() 
                { Name = "Activity 3", Complete = false, 
                    DueDate = startDate.AddDays(7), Project = "Project 1" });
            Activities.Add(new Activity() 
                { Name = "Activity 4", Complete = false, 
                    DueDate = startDate.AddDays(9), Project = "Project 1" });
            Activities.Add(new Activity() 
                { Name = "Activity 5", Complete = false, 
                    DueDate = startDate.AddDays(14), Project = "Project 1" });
            Activities.Add(new Activity() 
                { Name = "Activity A", Complete = true, 
                    DueDate = startDate.AddDays(2), Project = "Project 2" });
            Activities.Add(new Activity() 
                { Name = "Activity B", Complete = false, 
                    DueDate = startDate.AddDays(4), Project = "Project 2" });
            Activities.Add(new Activity() 
                { Name = "Activity C", Complete = true, 
                    DueDate = startDate.AddDays(5), Project = "Project 2" });
            Activities.Add(new Activity() 
                { Name = "Activity D", Complete = false, 
                    DueDate = startDate.AddDays(9), Project = "Project 2" });
            Activities.Add(new Activity() 
                { Name = "Activity E", Complete = false, 
                    DueDate = startDate.AddDays(18), Project = "Project 2" });

            var result = from act in Activities group act by act.Project into grp orderby grp.Key select grp;
            cvsActivities.Source = result;
        }

        private void PopulateProjects()
        {
            List<Project> Projects = new List<Project>();

            Project newProject = new Project();
            newProject.Name = "Project 1";
            newProject.Activities.Add(new Activity() 
                { Name = "Activity 1", Complete = true, DueDate = startDate.AddDays(4) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity 2", Complete = true, DueDate = startDate.AddDays(5) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity 3", Complete = false, DueDate = startDate.AddDays(7) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity 4", Complete = false, DueDate = startDate.AddDays(9) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity 5", Complete = false, DueDate = startDate.AddDays(14) });
            Projects.Add(newProject);

            newProject = new Project();
            newProject.Name = "Project 2";
            newProject.Activities.Add(new Activity() 
                { Name = "Activity A", Complete = true, DueDate = startDate.AddDays(2) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity B", Complete = false, DueDate = startDate.AddDays(3) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity C", Complete = true, DueDate = startDate.AddDays(5) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity D", Complete = false, DueDate = startDate.AddDays(9) });
            newProject.Activities.Add(new Activity() 
                { Name = "Activity E", Complete = false, DueDate = startDate.AddDays(18) });
            Projects.Add(newProject);

            newProject = new Project();
            newProject.Name = "Project 3";
            Projects.Add(newProject);

            cvsProjects.Source = Projects;
        }

    }

    public class ListGroupStyleSelector : GroupStyleSelector
    {
        protected override GroupStyle SelectGroupStyleCore(object group, uint level)
        {
            return (GroupStyle)App.Current.Resources["listViewGroupStyle"];
        }
    }

    public class Project
    {
        public Project()
        {
            Activities = new ObservableCollection<Activity>();
        }

        public string Name { get; set; }
        public ObservableCollection<Activity> Activities { get; private set; }
    }

    public class Activity
    {
        public string Name { get; set; }
        public DateTime DueDate { get; set; }
        public bool Complete { get; set; }
        public string Project { get; set; }
    }
}


App.xaml


<Application
    x:Class="ItemsControlGroupingSnippets.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ItemsControlGroupingSnippets">

    <Application.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="listViewItemTemplate">
                <StackPanel Width="320" Margin="10">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Name}" FontWeight="Bold" Style="{StaticResource BaseTextBlockStyle}"
                       Margin="2,0,0,0"/>
                        <TextBlock Text="{Binding DueDate}" Style="{StaticResource BodyTextBlockStyle}" TextWrapping="NoWrap"
                       Margin="20,0,0,0"/>
                    </StackPanel>
                    <CheckBox Content="Complete" IsChecked="{Binding Complete}" IsEnabled="False"/>
                </StackPanel>
            </DataTemplate>

            <GroupStyle x:Key="listViewGroupStyle">
                <GroupStyle.HeaderTemplate>
                    <DataTemplate>
                        <Grid Background="LightGray"  >
                            <TextBlock Text='{Binding Key}' Foreground="Black" Margin="10"
                           Style="{StaticResource SubheaderTextBlockStyle}" />
                        </Grid>
                    </DataTemplate>
                </GroupStyle.HeaderTemplate>
            </GroupStyle>
        </ResourceDictionary>
    </Application.Resources>
</Application>


Tópicos relacionados

ListView
GridView
Adicionando controles ListView e GridView
Exemplo de agrupamento GridView e SemanticZoom XAML

 

 

Mostrar:
© 2017 Microsoft