I'm facing an unexpected situation while working with ListView. I've this ListView with rows having a backgroung color according to its parity. It works quite good until I remove an element from the binded collection, and then two rows with the same background color appears together. Here's my code:
<ResourceDictionary>
<DataTemplate x:Key="EvenIndexDataTemplate">
<ViewCell>
<Grid BackgroundColor="LightGray"">
<!-- my content here -->
</Grid>
</ViewCell>
</DataTemplate>
<DataTemplate x:Key="OddIndexDataTemplate">
<ViewCell>
<Grid BackgroundColor="White"">
<!-- my content here -->
</Grid>
</ViewCell>
</DataTemplate>
<datatemp:EvenOddTemplateSelector x:Key="MyDataTemplate"
EvenTemplate="{StaticResource EvenIndexDataTemplate}"
OddTemplate="{StaticResource OddIndexDataTemplate}" />
</ResourceDictionary>
<ContentPage.Content>
<!-- something here -->
<ListView ItemsSource="{Binding ItemsSource}"
ItemTemplate="{StaticResource ItemTemplateResource}" />
<!-- something else here -->
</ContentPage.Content>
My DataTemplateSelector class:
public class EvenOddTemplateSelector : DataTemplateSelector
{
public DataTemplate EvenTemplate { get; set; }
public DataTemplate OddTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
var itemsView = (ListView)container;
return ((IList)itemsView.ItemsSource).IndexOf(item) % 2 == 0 ? EvenTemplate : OddTemplate;
}
What I want to get is to keep adjacents rows with different background color after removing an item. At this point ItemsSource gets modified only by Adding/Removing. I've not tried to insert an item. I don't need it for this feature I'm working on.
Any idea?
I just solved the issue. Here's what I did:
I created a customization of ViewCell
class and added three bindable properties ContainerItemsSource
, EvenBackgroundColor
and OddBackgroundColor
, then I override OnBindingContextChanged()
to make sure to set View
background color by its index within the collection.
You can check it out on this new brach on github repo.
Basically the idea is to use it on this way:
<ListView ItemsSource="{Binding YOUR_ITEMS_SOURCE}">
<ListView.ItemTemplate>
<DataTemplate>
<local:EvenOddCell ContainerItemsSource="{Binding YOUR_ITEMS_SOURCE,
Source={x:Reference YOUR_PAGE_BINDING_CONTEXT}}"
EvenBackgroundColor="AliceBlue"
OddBackgroundColor="White">
<!-- YOUR CELL CONTENT -->
</local:EvenOddCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My custom EvenOddCell
:
public class EvenOddCell : ViewCell
{
public Color EvenBackgroundColor
{
get => (Color)GetValue(EvenBackgroundColorProperty);
set => SetValue(EvenBackgroundColorProperty, value);
}
public Color OddBackgroundColor
{
get => (Color)GetValue(OddBackgroundColorProperty);
set => SetValue(OddBackgroundColorProperty, value);
}
public IList ContainerItemsSource
{
get => (IList)GetValue(ContainerItemsSourceProperty);
set => SetValue(ContainerItemsSourceProperty, value);
}
public static BindableProperty EvenBackgroundColorProperty = BindableProperty.Create(
nameof(EvenBackgroundColor), typeof(Color), typeof(EvenOddCell), default(Color));
public static BindableProperty OddBackgroundColorProperty = BindableProperty.Create(
nameof(OddBackgroundColor), typeof(Color), typeof(EvenOddCell), default(Color));
public static BindableProperty ContainerItemsSourceProperty = BindableProperty.Create(
nameof(ContainerItemsSource), typeof(IList), typeof(EvenOddCell),
default(IList), propertyChanged: OnContainerItemsSourcePropertyChanged);
private static void OnContainerItemsSourcePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
if (newValue != null && newValue is INotifyCollectionChanged)
{
((INotifyCollectionChanged)newValue).CollectionChanged += (s, e) =>
{
if (e.Action != NotifyCollectionChangedAction.Add)
{
((EvenOddCell)bindable).OnBindingContextChanged();
}
};
}
}
protected override void OnBindingContextChanged()
{
base.OnBindingContextChanged();
if (BindingContext != null && ContainerItemsSource is IList)
{
var idx = ContainerItemsSource.IndexOf(BindingContext);
View.BackgroundColor = idx % 2 == 0 ? EvenBackgroundColor : OddBackgroundColor;
}
}
}