Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ios] ListView.SelectedIndex set during item insertion is offset #16216

Open
Xiaoy312 opened this issue Apr 10, 2024 · 1 comment
Open

[ios] ListView.SelectedIndex set during item insertion is offset #16216

Xiaoy312 opened this issue Apr 10, 2024 · 1 comment
Labels
area/listview 📃 Categorizes an issue or PR as relevant to the ListView control difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working platform/ios 🍎 Categorizes an issue or PR as relevant to the iOS platform triage/untriaged Indicates an issue requires triaging or verification

Comments

@Xiaoy312
Copy link
Contributor

Current behavior

If you attempt to set the selection during list mutation, the set selection will be offset on iOS.

Expected behavior

^ should not happen.

How to reproduce it (as minimally and precisely as possible)

[TestMethod]
[RunsOnUIThread]
public async Task When_SelectionChanged_Midst_ListMutation_AsdAsd3()
{
	var source = new ObservableCollection<int> { 1, 11, 12, 2 };
	var SUT = new ListView
	{
		ItemsSource = source,
		SelectionMode = ListViewSelectionMode.Single,
	};

	await UITestHelper.Load(SUT);

	Assert.AreEqual(-1, SUT.SelectedIndex, "[pre-insert]SUT.SelectedIndex should be -1");
	Assert.IsNull(SUT.SelectedItem, "[pre-insert]SUT.SelectedItem should be null");

	(int Index, object Item) snapshot = (int.MinValue, default);
	SUT.ContainerContentChanging += (s, e) =>
	{
		if (e.Item as int? == 111)
		{
			e.ItemContainer.IsSelected = true;
			snapshot = (SUT.SelectedIndex, SUT.SelectedItem);
		}
	};
	source.Insert(index: 2, 111);
	await UITestHelper.WaitForIdle();

	Assert.AreEqual(2, snapshot.Index, "[mid-insert]snapshot.Index should be 2");  // actual: 2
	Assert.AreEqual(111, snapshot.Item, "[mid-insert]snapshot.Item should be 111"); // actual: 111
	Assert.AreEqual(2, SUT.SelectedIndex, "[post-insert]SUT.SelectedIndex should be 2"); // actual: 3
	Assert.AreEqual(111, SUT.SelectedItem, "[post-insert]SUT.SelectedItem should be 111"); // actual: 12
}

Workaround

No response

Works on UWP/WinUI

Yes

Environment

Uno.WinUI / Uno.WinUI.WebAssembly / Uno.WinUI.Skia

NuGet package version(s)

No response

Affected platforms

iOS

IDE

Visual Studio 2022

IDE version

No response

Relevant plugins

No response

Anything else we need to know?

note that on windows, LV::ContainerContentChanging will only get invoked once per app-launch (or until container cache gets purged...), so the test only work once...

@Xiaoy312 Xiaoy312 added kind/bug Something isn't working platform/ios 🍎 Categorizes an issue or PR as relevant to the iOS platform triage/untriaged Indicates an issue requires triaging or verification area/listview 📃 Categorizes an issue or PR as relevant to the ListView control difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. labels Apr 10, 2024
@Xiaoy312
Copy link
Contributor Author

slightly updated the test a bit

code
[TestMethod]
[RunsOnUIThread]
public async Task When_SelectionChanged_Midst_ListMutation_AsdAsd3()
{
	var states = new List<(int Index, int? Item, string Context)>();
	var source = new ObservableCollection<int>{ 1, 11, 12, 2, 3 };
	var SUT = new ListView
	{
		ItemsSource = source,
		SelectionMode = ListViewSelectionMode.Single,
	};
	SUT.SelectedIndex = 3;

	void SaveState(string context) => states.Add((SUT.SelectedIndex, SUT.SelectedItem as int?, context));

	await UITestHelper.Load(SUT);
	SaveState("0 pre-insert");

	SUT.ContainerContentChanging += (s, e) =>
	{
		SaveState("1 mid-insert before re-selection");
		if (e.Item as int? == 111)
		{
			e.ItemContainer.IsSelected = true;
		}
		SaveState("2 mid-insert after re-selection");
	};
	source.Insert(index: 2, 111);
	await UITestHelper.WaitForIdle();
	SaveState("3 post-insert");

	Assert.AreEqual(4, states.Count, "4 snapshots are expected.");
	Assert.AreEqual((3, 2), (states[0].Index, states[0].Item), states[0].Context); // selection should be value=2 at index=3
	Assert.AreEqual((4, 2), (states[1].Index, states[1].Item), states[1].Context); // selection should still be value=2 at index=4 (at this point, the index should've been already updated)
	Assert.AreEqual((2, 111), (states[2].Index, states[2].Item), states[2].Context); // selection should now be value=111 at index=2
	Assert.AreEqual((2, 111), (states[3].Index, states[3].Item), states[3].Context); // selection should still be value=111 at index=2
}

observation:

win,skia: states // new List<(int Index, int? Item, string Context)>();
Count = 4
    [0]: (3, 2, "0 pre-insert")
+   [1]: (4, 2, "1 mid-insert before re-selection")
    [2]: (2, 111, "2 mid-insert after re-selection")
+   [3]: (2, 111, "3 post-insert")

ios: states // new List<(int Index, int? Item, string Context)>();
Count = 4
    [0]: (3, 2, "0 pre-insert")
-   [1]: (3, 2, "1 mid-insert before re-selection")
    [2]: (2, 111, "2 mid-insert after re-selection")
-   [3]: (3, 12, "3 post-insert")

^ notice that on every other platform the offset correction occurs before ContainerContentChanging,
^ but on iOS, it happen afterward.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/listview 📃 Categorizes an issue or PR as relevant to the ListView control difficulty/tbd Categorizes an issue for which the difficulty level needs to be defined. kind/bug Something isn't working platform/ios 🍎 Categorizes an issue or PR as relevant to the iOS platform triage/untriaged Indicates an issue requires triaging or verification
Projects
None yet
Development

No branches or pull requests

1 participant