I am populating a screen with a CollectionView and I'd like to preselect the SelectedItem. On Android (left screenshot), this works fine, but not on iOS (right screenshot) - only manual selection by the user seems to change the UI.
To reproduce, use the standard MAUI template app, replace the XAML of the MainPage with
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MyMAUIApp.MainPage">
<CollectionView ItemSizingStrategy="MeasureAllItems" BackgroundColor="Yellow"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
SelectionMode="Single">
<CollectionView.ItemsLayout>
<GridItemsLayout Orientation="Vertical" Span="2"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid HeightRequest="50" WidthRequest="50">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor" Value="Red"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Label Text="Text" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentPage>
and the C# with
using System.Collections.ObjectModel;
namespace MyMAUIApp;
public partial class MainPage : ContentPage {
public MainPage() {
InitializeComponent();
BindingContext = this;
SelectedItem = Items[0];
OnPropertyChanged(nameof(SelectedItem));
}
public ObservableCollection<string> Items { get; } = new ObservableCollection<string>(new List<string> {
"A", "B", "C", "D"
});
public string SelectedItem { get; set; }
}
Is this a MAUI bug? Can I avoid it somehow? In the situation where I encounter this, I have some degree of success with refreshing the Items
after a short delay and/or subsequently invoking OnPropertyChanged(nameof(Items))
but not always.
Moving the code to OnAppearing()
, as suggested in the comments, doesn't work:
protected override void OnAppearing() {
base.OnAppearing();
SelectedItem = Items[0];
OnPropertyChanged(nameof(SelectedItem));
}
An example of how to make it work, but in a really awkward way:
public MainPage() {
InitializeComponent();
BindingContext = this;
_ = Task.Run(async () => {
await Task.Delay(100);
Dispatcher.Dispatch(() => {
SelectedItem = Items[0];
OnPropertyChanged(nameof(SelectedItem));
});
});
}
Yes, it is a potential issue on iOS. For now, setting the SelectedItem
property from ViewModel
is not working on iOS. And it is a known issue that is being tracked in the links below, you can follow up there.
https://github.com/dotnet/maui/issues/13059
https://github.com/dotnet/maui/issues/13072
As a workaround(awkaward however useful) suggested by Glorfindel like below:
_ = Task.Run(async () => {
await Task.Delay(100);
Dispatcher.Dispatch(() => {
SelectedStates = new ObservableCollection<object>(ss);
OnPropertyChanged(nameof(SelectedStates));
});
});