1 Comments

GroupedListView

Presenting the user a long list of data e.g. persons in an address book can be a bit overwhelming as there is no structure for the user to guide him through the list. So if we have a couple of entries that can be easily grouped it can really help the user while he is scrolling the list.

  1. Listing your entries
  2. Grouping the entries
  3. Enable Groupnavigation

Listing your entries

So lets create a new XAML page and add the list to it. I’ll be using the TextCell for this demo but Xamarin.Forms comes with many different default cell templates you can choose from.

<ListView x:Name="TheListView" ItemsSource="{Binding BindingContext}" ItemSelected="TheListViewOnItemSelected">

<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Fullname}" Detail="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

The binding context is set in the code behind.

var data = new List<Person>();

for (var i = 0; i < 50; ++i)
{
data.Add(new Person(NameGenerator.GenRandomFirstName(), NameGenerator.GenRandomLastName(), "ID " + i));
}

BindingContext = data;

 

Grouping the entries

In a next step lets group our contact list. First lets enable our ListView to accept groupings.

<ListView x:Name="TheListView" 
...
IsGroupingEnabled="True"
GroupDisplayBinding="{Binding Key}">

...

</ListView>

Next we have to group our list of people

var data = new List<Person>();

for (var i = 0; i < 50; ++i)
{
data.Add(new Person(NameGenerator.GenRandomFirstName(), NameGenerator.GenRandomLastName(), "ID " + i));
}

var groupedData =
data.OrderBy(p => p.Lastname)
.GroupBy(p => p.Lastname[0].ToString())
.Select(p => new ObservableGroupCollection<string, Person>(p))
.ToList();

BindingContext = new ObservableCollection<ObservableGroupCollection<string, Person>>(groupedData);

By using LINQ to order and group the people by their last name we have a fast and save way to do this. LINQ will return a list of IGrouping. Note that by using the first character we will only be taking the first letter as the key. So now lets have a look at the ObservableGroupCollection:

public class ObservableGroupCollection<S, T> : ObservableCollection<T>
{
private readonly S _key;

public ObservableGroupCollection(IGrouping<S, T> group)
: base(group)
{
_key = group.Key;
}

public S Key
{
get { return _key; }
}
}

The reason for inheriting from ObservableCollection is to allow you to add or remove items to an existing group e.g. adding or removing a person from your phone book. In my example the key will be of type string and the collection is of type IEnumerable<Person>.

Styling the header

As with the cell the header can also be styled by overwriting the DataTemplate:

<ListView x:Name="TheListView" ItemsSource="{Binding BindingContext}" ItemSelected="TheListViewOnItemSelected"
IsGroupingEnabled="True"
GroupDisplayBinding="{Binding Key}">

<ListView.GroupHeaderTemplate>
<DataTemplate>
<ViewCell>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
BackgroundColor="Navy">
<Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Label Text="{Binding Key}" FontSize="Small" TextColor="Lime" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>

...

</ListView>

Yeah I’m no designer so sorry if your eyes hurt when you see this one… ;)

Enable group navigation

The concepts differ for group navigation from platform to platform but you can enable it by binding the GroupShortNameBinding attribute to the key.

<ListView x:Name="TheListView"
...
IsGroupingEnabled="True"
GroupDisplayBinding="{Binding Key}"
GroupShortNameBinding="{Binding Key}">

...

</ListView>

Group navigation only is available on iOS and Windows Phone so make sure you test on those platforms. And as you will see the concepts are also quite different on each platform.

Conclusion

Enabling ListView for displaying a list of data in groups is really simple and can be solved very easily with XAML and LINQ. But be aware that the ListView can also be a real performance hog, when you go down the customization route (especially on iOS). So try to stick to the default templates and if you must use a custom cell be sure to follow the performance tips provided by the Xamarin.Forms team.

You can find this little project on GitHub.

Comments

Comment by Elton Ventura

Thanks for the help! I was looking for it!

Post comment