Skip to content

Commit

Permalink
Fix for CollectionView with RefreshView when ObservableCollection<T>.…
Browse files Browse the repository at this point in the history
…Clear() throws System.ArgumentOutOfRangeException (#26573)

* commit for 23868

* Fix code updated

* updated fix code with more appropriate return value

---------

Co-authored-by: praveenkumarkarunanithi <[email protected]>
  • Loading branch information
SuthiYuvaraj and praveenkumarkarunanithi authored Jan 6, 2025
1 parent 7e325d0 commit 0513686
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ internal int ItemsCount()
internal object ElementAt(int index)
{
if (_itemsSource is IList list)
return list[index];
return (index >= 0 && index < list.Count) ? list[index] : null;

int count = 0;
foreach (var item in _itemsSource)
Expand All @@ -289,7 +289,7 @@ internal object ElementAt(int index)
count++;
}

return -1;
return null;
}

internal int IndexOf(object item)
Expand Down
44 changes: 44 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue23868.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?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="Maui.Controls.Sample.Issues.Issue23868"
xmlns:local="clr-namespace:Maui.Controls.Sample.Issues"
x:Name="ThisMainPage"
Title="Main Page">
<StackLayout>
<Label Text="Pull to refresh twice to replicate the issue"
HorizontalOptions="Center"
VerticalOptions="Center"
FontSize="16"
Margin="10"
TextColor="Red" />
<RefreshView x:Name="refreshView" Command="{Binding PullToRefreshCommand}" Refreshing="OnRefreshing">
<CollectionView AutomationId="CollectionView" x:Name="collectionView" ItemsSource="{Binding Items}">
<CollectionView.Header>
<Grid ColumnDefinitions="2*,*"
HorizontalOptions="CenterAndExpand"
IsVisible="{Binding Source={x:Reference collectionView}, Path=ItemsSource.Count, FallbackValue=False}">
<Label Grid.Column="0"
Text="Items Count:"
VerticalTextAlignment="Center"
HorizontalOptions="EndAndExpand"/>
<Label Grid.Column="1"
Text="{Binding Items.Count}"
VerticalTextAlignment="Center"
HorizontalOptions="StartAndExpand"/>
</Grid>
</CollectionView.Header>
<CollectionView.ItemTemplate>
<DataTemplate>
<Label Text="{Binding}" HorizontalOptions="Center" VerticalOptions="Center"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>

<StackLayout Orientation="Horizontal" HorizontalOptions="Center" Margin="10">
<Button Text="UpdateData" AutomationId="UpdateData" Clicked="OnUpdateDataClicked"/>
<Button Text="ClearData" Clicked="OnClearDataClicked"/>
</StackLayout>
</StackLayout>
</ContentPage>
75 changes: 75 additions & 0 deletions src/Controls/tests/TestCases.HostApp/Issues/Issue23868.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#nullable enable
using System.Collections.ObjectModel;
using System.Text.Json;

namespace Maui.Controls.Sample.Issues
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[Issue(IssueTracker.Github, 23868, "CollectionView with RefreshView Throws Exception During Pull-to-Refresh Actions", PlatformAffected.iOS)]
public partial class Issue23868: ContentPage
{
private ObservableCollection<string> _items = new ObservableCollection<string>();

public ObservableCollection<string> Items
{
get => _items;
set
{
_items = value;
collectionView.ItemsSource = _items;
}
}

public Command PullToRefreshCommand { get; }

public Issue23868()
{
InitializeComponent();
Items = new ObservableCollection<string>();
BindingContext = this;

PullToRefreshCommand = new Command(async () => await SimulateHttpRequest());
}

private async Task SimulateHttpRequest()
{
refreshView.IsRefreshing = true;

// Simulate delay for data fetching
await Task.Delay(200);

// Simulated local JSON data
string jsonData = "[\"Local Item 1\", \"Local Item 2\", \"Local Item 3\"]";

// Parse the local data as a response
var items = JsonSerializer.Deserialize<string[]>(jsonData);

// Update ObservableCollection with fetched data
if (items != null)
{
Items.Clear();
foreach (var item in items)
{
Items.Add(item);
}
}

refreshView.IsRefreshing = false;
}

private async void OnUpdateDataClicked(object sender, EventArgs e)
{
await SimulateHttpRequest();
}

private void OnClearDataClicked(object sender, EventArgs e)
{
Items.Clear();
}

private void OnRefreshing(object sender, EventArgs e)
{
PullToRefreshCommand.Execute(null);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#if TEST_FAILS_ON_CATALYST //Swipe actions cannot be performed on the macOS test server
using NUnit.Framework;
using UITest.Appium;
using UITest.Core;

namespace Microsoft.Maui.TestCases.Tests.Issues
{
internal class Issue23868 : _IssuesUITest
{
public Issue23868(TestDevice device) : base(device) { }

public override string Issue => "CollectionView with RefreshView Throws Exception During Pull-to-Refresh Actions";

[Test]
[Category(UITestCategories.CollectionView)]
public void CollectionViewWithHeaderAndRefreshViewShouldNotCrashOnPullToRefresh()
{
App.WaitForElement("UpdateData");
App.Tap("UpdateData");
App.WaitForElement("CollectionView");
App.ScrollUp("CollectionView", ScrollStrategy.Gesture, swipeSpeed: 7000);
App.WaitForElement("CollectionView");
App.ScrollUp("CollectionView", ScrollStrategy.Gesture, swipeSpeed: 7000);
App.WaitForElement("CollectionView");
}
}
}
#endif

0 comments on commit 0513686

Please sign in to comment.