Skip to content

Commit 8581995

Browse files
committed
fix(ItemsControl): [Android] Adjust collection update reset for ComboBox
1 parent 31c5cc9 commit 8581995

File tree

4 files changed

+165
-3
lines changed

4 files changed

+165
-3
lines changed

src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ComboBox.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33
using System.Linq;
44
using System.Text;
55
using System.Threading.Tasks;
6+
using System.Collections.Specialized;
67
using Microsoft.VisualStudio.TestTools.UnitTesting;
78
using Uno.UI.RuntimeTests.Helpers;
89
using Windows.UI;
910
using Windows.UI.Xaml;
1011
using Windows.UI.Xaml.Controls;
1112
using Windows.UI.Xaml.Media;
1213
using static Private.Infrastructure.TestServices;
14+
using System.Collections.ObjectModel;
15+
1316
#if NETFX_CORE
1417
using Uno.UI.Extensions;
1518
#elif __IOS__
@@ -314,5 +317,81 @@ public void When_Index_Is_Explicitly_Set_To_Negative_After_Out_Of_Range_Value()
314317
comboBox.Items.Add(new ComboBoxItem());
315318
Assert.AreEqual(-1, comboBox.SelectedIndex); // Will no longer become 2
316319
}
320+
321+
[TestMethod]
322+
public async Task When_Collection_Reset()
323+
{
324+
var SUT = new ComboBox();
325+
try
326+
{
327+
WindowHelper.WindowContent = SUT;
328+
329+
var c = new MyObservableCollection<string>();
330+
c.Add("One");
331+
c.Add("Two");
332+
c.Add("Three");
333+
334+
SUT.ItemsSource = c;
335+
336+
await WindowHelper.WaitForIdle();
337+
338+
Assert.AreEqual(SUT.Items.Count, 3);
339+
340+
using (c.BatchUpdate())
341+
{
342+
c.Add("Four");
343+
c.Add("Five");
344+
}
345+
346+
SUT.IsDropDownOpen = true;
347+
348+
// Items are materialized when the popup is opened
349+
await WindowHelper.WaitForIdle();
350+
351+
Assert.AreEqual(SUT.Items.Count, 5);
352+
Assert.IsNotNull(SUT.ContainerFromItem("One"));
353+
Assert.IsNotNull(SUT.ContainerFromItem("Four"));
354+
Assert.IsNotNull(SUT.ContainerFromItem("Five"));
355+
}
356+
finally
357+
{
358+
SUT.IsDropDownOpen = false;
359+
}
360+
}
361+
362+
public class MyObservableCollection<TType> : ObservableCollection<TType>
363+
{
364+
private int _batchUpdateCount;
365+
366+
public IDisposable BatchUpdate()
367+
{
368+
++_batchUpdateCount;
369+
370+
return Uno.Disposables.Disposable.Create(Release);
371+
372+
void Release()
373+
{
374+
if (--_batchUpdateCount <= 0)
375+
{
376+
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
377+
}
378+
}
379+
}
380+
381+
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
382+
{
383+
if (_batchUpdateCount > 0)
384+
{
385+
return;
386+
}
387+
388+
base.OnCollectionChanged(e);
389+
}
390+
391+
public void Append(TType item) => Add(item);
392+
393+
public TType GetAt(int index) => this[index];
394+
}
395+
317396
}
318397
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
7+
namespace Uno.UI.Tests.Helpers
8+
{
9+
internal class ObservableCollectionEx<TType> : System.Collections.ObjectModel.ObservableCollection<TType>
10+
{
11+
private int _batchUpdateCount;
12+
13+
public IDisposable BatchUpdate()
14+
{
15+
++_batchUpdateCount;
16+
17+
return Uno.Disposables.Disposable.Create(Release);
18+
19+
void Release()
20+
{
21+
if (--_batchUpdateCount <= 0)
22+
{
23+
OnCollectionChanged(new System.Collections.Specialized.NotifyCollectionChangedEventArgs(System.Collections.Specialized.NotifyCollectionChangedAction.Reset));
24+
}
25+
}
26+
}
27+
28+
protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
29+
{
30+
if (_batchUpdateCount > 0)
31+
{
32+
return;
33+
}
34+
35+
base.OnCollectionChanged(e);
36+
}
37+
38+
public void Append(TType item) => Add(item);
39+
40+
public TType GetAt(int index) => this[index];
41+
}
42+
}

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,48 @@ public async Task When_ItemsSource_Changes_Items_VectorChanged_Triggered()
367367
Assert.AreEqual(0, listView.Items.Count);
368368
}
369369

370+
[TestMethod]
371+
public async Task When_Collection_Reset()
372+
{
373+
var count = 0;
374+
var panel = new StackPanel();
375+
376+
var SUT = new ItemsControl()
377+
{
378+
ItemsPanelRoot = panel,
379+
ItemContainerStyle = BuildBasicContainerStyle(),
380+
InternalItemsPanelRoot = panel,
381+
ItemTemplate = new DataTemplate(() =>
382+
{
383+
count++;
384+
return new Border();
385+
})
386+
};
387+
SUT.ApplyTemplate();
388+
389+
var c = new ObservableCollectionEx<string>();
390+
c.Add("One");
391+
c.Add("Two");
392+
c.Add("Three");
393+
394+
SUT.ItemsSource = c;
395+
Assert.AreEqual(count, 3);
396+
397+
Assert.AreEqual(SUT.Items.Count, 3);
398+
399+
using (c.BatchUpdate())
400+
{
401+
c.Add("Four");
402+
c.Add("Five");
403+
}
404+
405+
Assert.AreEqual(SUT.Items.Count, 5);
406+
Assert.AreEqual(count, 5);
407+
Assert.IsNotNull(SUT.ContainerFromItem("One"));
408+
Assert.IsNotNull(SUT.ContainerFromItem("Four"));
409+
Assert.IsNotNull(SUT.ContainerFromItem("Five"));
410+
}
411+
370412
private Style BuildBasicContainerStyle() =>
371413
new Style(typeof(Windows.UI.Xaml.Controls.ListViewItem))
372414
{

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,6 @@ protected virtual void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e
639639

640640
IsGrouping = (e.NewValue as ICollectionView)?.CollectionGroups != null;
641641
Items.SetItemsSource(UnwrapItemsSource() as IEnumerable);
642-
UpdateItems(null);
643642
ObserveCollectionChanged();
644643
TryObserveCollectionViewSource(e.NewValue);
645644
}
@@ -918,8 +917,8 @@ void LocalCleanupContainer(object container)
918917
}
919918

920919
ItemsPanelRoot.Children.Clear();
921-
RequestLayoutPartial();
922-
return;
920+
921+
// Fall-through and materialize the call collection.
923922
}
924923
else if (args.Action == NotifyCollectionChangedAction.Remove
925924
&& args.OldItems.Count == 1)

0 commit comments

Comments
 (0)