Windows 8–Grid View

GridView is one of the most powerful out-of-the-box controls in Windows 8, but fully understanding how to use it is not necessarily trivial.  GroupedByCityThe complexity, I believe, comes because GridViews are often used to hold groups of collections, rather than simple collections.  The GridView template assumes that it will be displaying groups of collections of items, and this can make working with the GridView, initially, more complex than it would otherwise be.

Gridview shares all the same methods, properties and events with ListView; all of which they inherit from their base classes.  The two controls are nearly identical; the key difference being that ListView is used to scroll items vertically, while GridView is used to scroll items horizontally. 

Getting Started

Getting started with GridView is nearly trivial, as I showed in this article.  Today, we’ll take a look at a more realistic use of GridView however, one that displays groups of collections, and that is not trivial. 

Let’s assume that our data consists of people, with each person having a first name, a last name and a city.

public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }

 

We’d like to display these people in a GridView, but organized (grouped) by city.  The trick is to create a Group class that will allow you to have a key on which you’ll group the people (in this case city) and a list of people who match that key,

 

public class Group<TKey, TItem>
{
public TKey Key { get; set; }
public IList<TItem> Items { get; set; }
}

To generate your initial (ungrouped) list of people you might go out to a service, or read in XML, or in our case, you might generate names and cities at random. To do so, we’ll have three arrays,

private static readonly string[] firstNames = { "Adam", "Bob", "Carl", "David", "Edgar", "Frank", "George", "Harry", "Isaac", "Jesse", "Ken", "Larry" };
private static readonly string[] lastNames = { "Aaronson", "Bobson", "Carlson", "Davidson", "Enstwhile", "Ferguson", "Harrison", "Isaacson", "Jackson", "Kennelworth", "Levine" };
private static readonly string[] cities = { "Boston", "New York", "LA", "San Francisco", "Phoenix", "San Jose", "Cincinnati", "Bellevue" };

And you’ll need a method to generate a given number of people randomly mixing names and cities,

public static IEnumerable<Person> CreatePeople(int count)
{
var people = new List<Person>();

var r = new Random();

for (int i = 0; i < count; i++)
{
var p = new Person()
{
FirstName = firstNames[r.Next(firstNames.Length)],
LastName = lastNames[r.Next(lastNames.Length)],
City = cities[r.Next(cities.Length)]
};
people.Add(p);
}
return people;
}
 

Creating the GridView

Let’s turn now to the view.  In MainPage.xaml you’ll add a GridView control which will bind its itemsSource to a CollectionViewSource. 

 
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<GridView x:Name="myGridView"
ItemsSource="{Binding Source={StaticResource cvs}}">

 
The CollectionViewSource manages the collection of lists, and is created in the Resources Section.  Be sure to set the IsSourceGrouped property to True and set the ItemsPath to the list of objects (in our case, the Items property in the  Group class.)
 
<Page.Resources>
<CollectionViewSource x:Name="cvs"
IsSourceGrouped="True"
ItemsPath="Items" />
</Page.Resources>

Within the GridView itself we want to determine how the groups will be organized, and for that we use the ItemsControl.ItemsPanel,

<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
To ensure that there is sufficient room between each entry, we’ll want to add some padding around each item. We do that with the ItemsControl.ItemContainerStyle,
 
<ItemsControl.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Left" />
<Setter Property="Padding"
Value="5" />
</Style>
</ItemsControl.ItemContainerStyle>

Next we want to determine how each group will be laid out. This consists of two templates: one for the header and one for the items themselves.  The Headertemplate will, in our case, display the city which is, you’ll remember the Key property in the Group

class. 
 
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding Key}"
FontSize="26.67" />
</DataTemplate>
</GroupStyle.HeaderTemplate>

We then add an ItemsPanelTemplate to ensure that the members of each group are listed vertically and have an appropriate width,
 
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical"
ItemWidth="220" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
 

The Supporting Code

In the code behind I generate the 200 people into a list and then use a LINQ statement to obtain a list of Group objects, which I set as the source for the CollectionViewSource,

 


people = Person.CreatePeople( 200 ).ToList();
groupedPeople = ( from person in people
group person by person.City into g
orderby g.Key
select new Group<object, Person>
{
Key = g.Key.ToString(),
Items = g.ToList()
} ).ToList();
cvs.Source = groupedPeople;
 
Notice that I don’t need an item template as I’ve overridden the ToString method of Person,
 
public override string ToString()
{
return string.Format("{0} {1} ({2})", FirstName, LastName, City);
}

The net effect is the gridview shown in the figure at the top of this posting.

 
 
 
 

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in Essentials, Linq, Mini-Tutorial, Windows 8 and tagged . Bookmark the permalink.