Skip to main content

Grouped ListView with Alternate Row Color in Xamarin.Forms

·3 mins

As a follow-up on my previous post about alternate row colors in a ListView, this question was posted on StackOverflow. The poster of the question wants to implement alternate row coloring on his grouped ListView.

How can I implement it with a grouped listview? I want to have the alternate row color inside every group of the listview, I already tried to implement it with the grouped Listview, but is always giving me “System.InvalidCastException: Specified cast is not valid.” inside the DataTemplateSelector.

I started out thinking that it was a simple casting problem since the collection behind a ListView is different when using grouping. But the problem lies a bit deeper.

For the TL;DR people, the source code can be found here: https://github.com/jfversluis/GroupedListViewAlternateRowColor.

The Problem #

Observe the initial DataTemplateSelector for the alternate row coloring below.

With the above code, I take the ItemsSource from the ListView and find the index in the collection.

When you are using a grouping, it will be a 2d collection. The question asker used the MvvmHelpers by James Montemagno which includes a Grouping. When using this it looks like this:

public ObservableCollection<Grouping<string, string>> ListItems

This basically means you have one list which holds a key/value pair. The key being a string in this case, and the value is another collection in this case also of type string. For instance, a list will look like this:

  • Marvel
    • 0 Iron Man
    • 1 Captain America
  • DC
    • 0 Batman
    • 1 Superman

Marvel and DC are the groups and the subitems for each are list items underneath the respective groups. The number indicates the index when calling the IndexOf method on that item.

On a first thought, I just changed the cast in the above code from a List to the ObservableCollection<Grouping<string, string» and be done with it. But on second thought, when you then determine the index, you will get the index of an item within that single group. While this might produce the right result for most cases, it could also have some unwanted side-effects.

The Solution: Implementing alternate row coloring for a grouped ListView #

To always produce a right result I implemented a mechanism that flattens the list and then decides the index of the item. Find the new code underneath.

Now, we cast the ItemsSource to the right type of collection and create a flat copy of it. Flat meaning that we take out the groups and just put all items into one list. This way, we can decide the right index over the whole list.

If we think back about the list from above when flattened, it will now look like:

  • 0 Iron Man
  • 1 Captain America
  • 2 Batman
  • 3 Superman

Just like before, have a look at the number in front: the index is now a nice list of incrementing indexes. With that list, we can just call the IndexOf again and the odd and even templates work like they worked before.

Grouped ListView with Alternate Row Color

Summary #

The sample code for this sample can be found on my GitHub account: https://github.com/jfversluis/GroupedListViewAlternateRowColor.

Unfortunately, before this post was finished the poster of the question made clear that this solution is not good for him. Upon sharing his code, I saw that he was adding items to the list dynamically, making it unsuitable for this approach.

Still, I hope this code is useful to other people and it was fun to see my blog being referenced as a sample for a question.