Listview non mis à jour lorsque isVisible est défini sur true

J'essaie de faire un ListView avec des lignes cliquables. Lorsque vous click une ligne, elle définit une stacklayout enfant à la visibilité true. Cela fonctionne bien dans Android, mais pas dans iOS. Peut-être que je le fais dans le mauvais sens. Je suis toujours un débutant, une idée de comment réparer cela ou toute autre meilleure approche? Le problème est qu'il s'ouvre sur ios donc la visibilité change, mais il ne met pas à jour la hauteur de la cellule. La cellule se met à jour hors de l'écran, par exemple si vous faites défiler jusqu'à ce que vous ne puissiez plus voir la cellule ouverte, puis redescendez. Vous verrez qu'il a mis à jour la hauteur.

J'ai essayé d'utiliser un moteur de rendu personnalisé, mais je n'ai aucune idée par où commencer.

C'est mon xaml:

 <?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="Lisa.Excelsis.Mobile.AssessmentPage" xmlns:local="clr-namespace:Lisa.Excelsis.Mobile;assembly=Lisa.Excelsis.Mobile"> <StackLayout> <local:SpecialListView x:Name="CategoryList" ItemsSource = "{Binding Categories}" HasUnevenRows="true" RowHeight="-1" GroupDisplayBinding="{Binding Name}" IsGroupingEnabled="true"> <local:SpecialListView.ItemTemplate> <DataTemplate> <ViewCell x:Name="ObservationCell"> <ViewCell.View> <StackLayout x:Name="ObservationContainer" HorizontalOptions="FillAndExpand" Orientation="Vertical" VerticalOptions="StartAndExpand" BackgroundColor="White"> <StackLayout x:Name="Observation" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" Padding="15, 10, 10, 10" BackgroundColor="White"> <StackLayout.GestureRecognizers> <TapGestureRecognizer Tapped="OpenItem"/> </StackLayout.GestureRecognizers> <Grid HorizontalOptions="FillAndExpand" > <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="35" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Label x:Name="ObservationOrder" Text="{Binding Criterion.Order, SsortingngFormat='{0}.'}" FontSize="18" VerticalOptions="StartAndExpand" Grid.Column="0" Grid.Row="0"/> <Label x:Name="ObservationTitle" Text="{Binding Criterion.Title}" FontSize="18" VerticalOptions="StartAndExpand" Grid.Column="1" Grid.Row="0"/> </Grid> </StackLayout> <StackLayout x:Name="ObservationButtons" HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" BackgroundColor="White" IsVisible="false" Padding="0, 0, 0, 20" ClassId = "{Binding Id, SsortingngFormat='ObservationButtons_{0}'}"> <Grid HorizontalOptions="Center" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="10" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> <ColumnDefinition Width="80" /> </Grid.ColumnDefinitions> <StackLayout Grid.Column="0" Grid.Row="0" > <Image Source="yesnobutton0.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" x:Name="yesImage"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetYesImage"/> </Image.GestureRecognizers> </Image> <Label Text="Ja" VerticalOptions="End" HorizontalOptions="Center"/> </StackLayout> <StackLayout Grid.Column="1" Grid.Row="0"> <Image Source="yesnobutton0.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" x:Name="noImage"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetNoImage"/> </Image.GestureRecognizers> </Image> <Label Text="Nee" VerticalOptions="End" HorizontalOptions="Center"/> </StackLayout> <Image Source="maybenot.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="3" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> <Image Source="skip.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="4" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> <Image Source="unclear.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="5" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> <Image Source="change.png" HeightRequest="60" WidthRequest="60" HorizontalOptions="Center" VerticalOptions="Start" Grid.Column="6" Grid.Row="0"> <Image.GestureRecognizers> <TapGestureRecognizer Tapped="SetMark"/> </Image.GestureRecognizers> </Image> </Grid> </StackLayout> </StackLayout> </ViewCell.View> </ViewCell> </DataTemplate> </local:SpecialListView.ItemTemplate> </local:SpecialListView> </StackLayout> 

Ceci est un exemple de comment cela fonctionne sur Android et comment je veux que cela fonctionne sur ios. Exemple de liste

J'ai reproduit votre problème dans un petit projet de test. Je préfère faire des changements de layout via la data binding, au lieu du code derrière.

Commençons par le model :

 <?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> 

Le Datatemplate est fondamentalement le même, mais:

  • le StackLayout n'a aucun clic-Listener
  • la visibilité de StackLayout est liée à IsSelected ( IsVisible="{Binding IsSelected}" )
  • le SelectedItem de ListView est lié à SelectedItem de notre ViewModel

Notre page définit simplement ViewModel tant que DataContext

 public partial class Page1 : ContentPage { public Page1() { InitializeComponent(); BindingContext = new Page1ViewModel(); } } 

Le ViewModel

  • implémente INotifyPropertyChanged pour notifier l'affichage sur les modifications de données
  • ajoute des objects factices à notre Collection Categories
  • possède une propriété SelectedItem qui met à jour la propriété IsSelected des catégories
 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] ssortingng 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()); } } 

Dernier point, mais non le moindre, mais le plus important, vous avez besoin d'un petit moteur de rendu personnalisé qui écrase celui par défaut. Nous appelons ReloadData() si le SelectedItem a changé.

 [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()); } } } } 

Résultat

Vue de liste avec des cellules dynamiques