Very quick Xamarin How-To this week with a simple converter. Alternating row colours in a CollectionView is quite often a design requirement and I wanted to create a simple, reusable converter to solve this.
The Converter
using System;
using System.Globalization;
using System.Linq;
using Xamarin.Forms;
namespace XhtCollectionViewAlternatingRowColor.Converters
{
public class IndexToColorConverter : IValueConverter
{
public Color EvenColor { get; set; }
public Color OddColor { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var collectionView = parameter as CollectionView;
if (collectionView?.ItemsSource is IEnumerable<object> items)
{
int index = items.ToList().IndexOf(value);
return index % 2 == 0 ? EvenColor : OddColor;
}
return EvenColor; // default fallback
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Using the Converter in XAML
<ContentPage
Title="Alternating Row Colors"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:XhtCollectionViewAlternatingRowColor.Converters"
xmlns:local="clr-namespace:XhtCollectionViewAlternatingRowColor"
x:Class="XhtCollectionViewAlternatingRowColor.MainPage">
<ContentPage.Resources>
<converters:IndexToColorConverter x:Key="IndexToColorConverterGrid" EvenColor="#0D92DB" OddColor="White" />
<converters:IndexToColorConverter x:Key="IndexToColorConverterText" EvenColor="White" OddColor="Black" />
</ContentPage.Resources>
<ContentPage.BindingContext>
<local:MainViewModel />
</ContentPage.BindingContext>
<ContentPage.Content>
<CollectionView x:Name="MyCollectionView" ItemsSource="{Binding Items}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid BackgroundColor="{Binding ., Converter={StaticResource IndexToColorConverterGrid}, ConverterParameter={x:Reference MyCollectionView}}">
<Label
Text="{Binding .}"
TextColor="{Binding ., Converter={StaticResource IndexToColorConverterText}, ConverterParameter={x:Reference MyCollectionView}}"
Margin="20" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage.Content>
</ContentPage>
There you go, nice and simple, easy to follow and reuse! As always, full source code available here.
Despite the fact that it works great, the ToList copy in each call of the converter seems a really bad example. A list of 10 items would create 20 list copies in your example.
I think it would be way cleverer to type check it and cast it to prevent all those allocations that on mobile are really not nessecary.
but none the less. a cool sample! keep up the cool blogs
Hi Bernhard,
That’s a very good point you make! I have updated the solution accordingly.
Good idea, but using Cast and IndexOf over the complete list for every single row will probably get slow when you have a lot of items (a lot of times I need multiple hundreds or even thousands).
So you should definetly use some kind of indexing for getting the position fast.
Or just invert the color assignment process: Iterate over the whole list one time and just set a Color property on a viewmodel for each position (0: Blue, 1: White, 2: Blue, 3: White …).
Thanks. On a separate topic: This page gets broken after a few seconds. Happens in Chrome and Edge. Has got to be some late loading script or HTML.