I reproduced your problem in a small test project. I prefer to make layout changes through data binding rather than behind the code.
Let's start with the Template :
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="App6.Page1"> <ListView x:Name="CategoryList" BackgroundColor="Gray" ItemsSource="{Binding Categories}" SelectedItem="{Binding SelectedItem}" HasUnevenRows="true" RowHeight="-1"> <ListView.ItemTemplate> <DataTemplate> <ViewCell x:Name="ObservationCell"> <ViewCell.View> <StackLayout x:Name="Observation" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" Padding="15, 10, 10, 10" BackgroundColor="White"> <Label x:Name="ObservationTitle" Text="{Binding Title}" FontSize="18" TextColor="Black" VerticalOptions="StartAndExpand"/> <StackLayout Orientation="Horizontal" IsVisible="{Binding IsSelected}"> <Image BackgroundColor="Fuchsia" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Green" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Yellow" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Blue" WidthRequest="40" HeightRequest="40"></Image> <Image BackgroundColor="Black" WidthRequest="40" HeightRequest="40"></Image> </StackLayout> </StackLayout> </ViewCell.View> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage>
The Datatemplate parameter is basic, but:
StackLayout does not have Click-Listener- Viscosity StackLayout bound to
IsSelected ( IsVisible="{Binding IsSelected}" ) SelectedItem ListView bound to SelectedItem our ViewModel
Our Page simply sets the ViewModel as a DataContext
public partial class Page1 : ContentPage { public Page1() { InitializeComponent(); BindingContext = new Page1ViewModel(); } }
ViewModel
- implements
INotifyPropertyChanged for notification of data changes. - adds some dummy elements to our
Categories collection - has a
SelectedItem property that updates the IsSelected property of categories
class Page1ViewModel : INotifyPropertyChanged { private Category _selectedItem; private ObservableCollection<Category> _categories = new ObservableCollection<Category>(); public event PropertyChangedEventHandler PropertyChanged; public ObservableCollection<Category> Categories { get { return _categories; } set { _categories = value; OnPropertyChanged(); } } public Category SelectedItem { get { return _selectedItem; } set { if (_selectedItem == value) return; if (_selectedItem != null) { _selectedItem.IsSelected = false; } _selectedItem = value; if (_selectedItem != null) { _selectedItem.IsSelected = true; } } } [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } public Page1ViewModel() { Categories.Add(new Category()); Categories.Add(new Category()); Categories.Add(new Category()); Categories.Add(new Category()); Categories.Add(new Category()); } }
And last but not least, but most importantly, you need a small custom renderer that overwrites the default value. We call ReloadData() if the SelectedItem has changed.
[assembly: ExportRenderer(typeof(ListView), typeof(MyListViewRenderer))] namespace App6.iOS.CustomRenderer { public class MyListViewRenderer : ListViewRenderer { protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == ListView.SelectedItemProperty.PropertyName) { Device.BeginInvokeOnMainThread(() => Control.ReloadData()); } } } }
Result

source share