Skip to content

Commit 4b63312

Browse files
committed
fix(itemscontrol): Fixed problem with internal assignment of indexes to elements in ItemsControl
fixes #8203
1 parent fc15fff commit 4b63312

File tree

2 files changed

+130
-5
lines changed

2 files changed

+130
-5
lines changed

src/Uno.UI.Tests/Windows_UI_XAML_Controls/ItemsControlTests/Given_ItemsControl.cs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
using Windows.UI.Xaml;
1212
using Windows.UI.Xaml.Controls;
1313
using Windows.UI.Xaml.Data;
14+
using FluentAssertions;
15+
using FluentAssertions.Execution;
1416

1517
namespace Uno.UI.Tests.ItemsControlTests
1618
{
@@ -135,6 +137,112 @@ public void When_OnItemsSourceChanged()
135137
Assert.AreEqual(1, count);
136138
}
137139

140+
[TestMethod]
141+
public void When_OnItemsSourceChanged_AfterRemove_ThenIndexesAreRecalculated()
142+
{
143+
void Operation(ObservableCollection<string> list)
144+
{
145+
list.RemoveAt(1);
146+
}
147+
148+
CheckItemsSourceChanged(Operation);
149+
}
150+
151+
[TestMethod]
152+
public void When_OnItemsSourceChanged_AfterInsert_ThenIndexesAreRecalculated()
153+
{
154+
void Operation(ObservableCollection<string> list)
155+
{
156+
list.Insert(2, "new item");
157+
}
158+
159+
CheckItemsSourceChanged(Operation);
160+
}
161+
162+
[TestMethod]
163+
public void When_OnItemsSourceChanged_AfterAdd_ThenIndexesAreRecalculated()
164+
{
165+
void Operation(ObservableCollection<string> list)
166+
{
167+
list.Add("new item at the end");
168+
}
169+
170+
CheckItemsSourceChanged(Operation);
171+
}
172+
173+
[TestMethod]
174+
public void When_OnItemsSourceChanged_AfterClear_ThenIndexesAreRecalculated()
175+
{
176+
void Operation(ObservableCollection<string> list)
177+
{
178+
list.Clear();
179+
}
180+
181+
CheckItemsSourceChanged(Operation);
182+
}
183+
184+
[TestMethod]
185+
public void When_OnItemsSourceChanged_AfterMove_ThenIndexesAreRecalculated()
186+
{
187+
void Operation(ObservableCollection<string> list)
188+
{
189+
list.Move(1, 3);
190+
}
191+
192+
CheckItemsSourceChanged(Operation);
193+
}
194+
195+
[TestMethod]
196+
public void When_OnItemsSourceChanged_AfterReplace_ThenIndexesAreRecalculated()
197+
{
198+
void Operation(ObservableCollection<string> list)
199+
{
200+
list[1] = "new index 1";
201+
}
202+
203+
CheckItemsSourceChanged(Operation);
204+
}
205+
206+
private static void CheckItemsSourceChanged(Action<ObservableCollection<string>> operation)
207+
{
208+
var source = new ObservableCollection<string>();
209+
210+
source.Add("item 0");
211+
source.Add("item 1");
212+
source.Add("item 2");
213+
source.Add("item 3");
214+
source.Add("item 4");
215+
216+
var panel = new StackPanel();
217+
var sut = new ItemsControl
218+
{
219+
ItemsPanelRoot = panel,
220+
InternalItemsPanelRoot = panel,
221+
ItemTemplate = new DataTemplate(() => { return new Border(); }),
222+
ItemsSource = source
223+
};
224+
225+
using var _ = new AssertionScope();
226+
227+
CheckIndexes();
228+
229+
operation(source);
230+
231+
CheckIndexes();
232+
233+
void CheckIndexes()
234+
{
235+
panel.Children­.Should().HaveCount(source.Count);
236+
237+
for (var i = 0; i < panel.Children.Count; i++)
238+
{
239+
var child = panel.Children[i];
240+
var index = child.GetValue(ItemsControl.IndexForItemContainerProperty);
241+
index.Should().Be(i);
242+
}
243+
}
244+
}
245+
138246
[TestMethod]
139247
public void When_CollectionViewSource()
140248
{

src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -995,6 +995,18 @@ void LocalCleanupContainer(object container)
995995
if (container is DependencyObject doContainer)
996996
{
997997
CleanUpContainer(doContainer);
998+
doContainer.ClearValue(IndexForItemContainerProperty);
999+
}
1000+
}
1001+
1002+
void ReassignIndexes(int startingIndex)
1003+
{
1004+
var children = ItemsPanelRoot.Children;
1005+
var count = children.Count;
1006+
for (var i = startingIndex; i<count; i++)
1007+
{
1008+
var container = children[i];
1009+
container.SetValue(IndexForItemContainerProperty, i);
9981010
}
9991011
}
10001012

@@ -1014,28 +1026,33 @@ void LocalCleanupContainer(object container)
10141026
else if (args.Action == NotifyCollectionChangedAction.Remove
10151027
&& args.OldItems.Count == 1)
10161028
{
1017-
var container = ItemsPanelRoot.Children[args.OldStartingIndex];
1029+
var index = args.OldStartingIndex;
1030+
var container = ItemsPanelRoot.Children[index];
10181031

1019-
ItemsPanelRoot.Children.RemoveAt(args.OldStartingIndex);
1032+
ItemsPanelRoot.Children.RemoveAt(index);
10201033

10211034
LocalCleanupContainer(container);
1035+
ReassignIndexes(index);
10221036
RequestLayoutPartial();
10231037
return;
10241038
}
10251039
else if (args.Action == NotifyCollectionChangedAction.Add
10261040
&& args.NewItems.Count == 1)
10271041
{
1028-
ItemsPanelRoot.Children.Insert(args.NewStartingIndex, (UIElement)LocalCreateContainer(args.NewStartingIndex));
1042+
var index = args.NewStartingIndex;
1043+
ItemsPanelRoot.Children.Insert(index, (UIElement)LocalCreateContainer(index));
1044+
ReassignIndexes(index+1);
10291045
RequestLayoutPartial();
10301046
return;
10311047
}
10321048
else if (args.Action == NotifyCollectionChangedAction.Replace
10331049
&& args.NewItems.Count == 1)
10341050
{
1035-
var container = ItemsPanelRoot.Children[args.NewStartingIndex];
1051+
var index = args.NewStartingIndex;
1052+
var container = ItemsPanelRoot.Children[index];
10361053
LocalCleanupContainer(container);
10371054

1038-
ItemsPanelRoot.Children[args.NewStartingIndex] = (UIElement)LocalCreateContainer(args.NewStartingIndex);
1055+
ItemsPanelRoot.Children[index] = (UIElement)LocalCreateContainer(index);
10391056
RequestLayoutPartial();
10401057
return;
10411058
}

0 commit comments

Comments
 (0)