Skip to content

Commit cc335ac

Browse files
Extend the fix for Recycling the focused element to non virtualized layouts (#1724)
* Ensure that we set the m_processingItesmSourceChange flag for non-virtualizing layouts as well as virtualizing ones. * update the corresponding test * Fix the test
1 parent e158eec commit cc335ac

File tree

2 files changed

+84
-74
lines changed

2 files changed

+84
-74
lines changed

dev/Repeater/APITests/RepeaterTests.cs

Lines changed: 47 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#endif
2121

2222
using ItemsRepeater = Microsoft.UI.Xaml.Controls.ItemsRepeater;
23+
using Layout = Microsoft.UI.Xaml.Controls.Layout;
2324
using ItemsSourceView = Microsoft.UI.Xaml.Controls.ItemsSourceView;
2425
using RecyclingElementFactory = Microsoft.UI.Xaml.Controls.RecyclingElementFactory;
2526
using RecyclePool = Microsoft.UI.Xaml.Controls.RecyclePool;
@@ -267,52 +268,63 @@ public void NestedRepeaterWithDataTemplateScenario()
267268
[TestMethod]
268269
public void VerifyFocusedItemIsRecycledOnCollectionReset()
269270
{
270-
List<string> items = new List<string> { "item0", "item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9" };
271-
ItemsRepeater repeater = null;
272-
const int targetIndex = 4;
273-
string targetItem = items[targetIndex];
274-
271+
List<Layout> layouts = new List<Layout>();
275272
RunOnUIThread.Execute(() =>
276273
{
277-
repeater = new ItemsRepeater() {
278-
ItemsSource = items,
279-
ItemTemplate = CreateDataTemplateWithContent(@"<Button Content='{Binding}'/>")
280-
};
281-
Content = repeater;
274+
layouts.Add(new MyCustomNonVirtualizingStackLayout());
275+
layouts.Add(new StackLayout());
282276
});
283-
284-
IdleSynchronizer.Wait();
285277

286-
RunOnUIThread.Execute(() =>
278+
foreach (var layout in layouts)
287279
{
288-
Log.Comment("Setting Focus on item " + targetIndex);
289-
Button toFocus = (Button)repeater.TryGetElement(targetIndex);
290-
Verify.AreEqual(targetItem, toFocus.Content as string);
291-
toFocus.Focus(FocusState.Keyboard);
292-
});
280+
List<string> items = new List<string> { "item0", "item1", "item2", "item3", "item4", "item5", "item6", "item7", "item8", "item9" };
281+
const int targetIndex = 4;
282+
string targetItem = items[targetIndex];
283+
ItemsRepeater repeater = null;
293284

294-
IdleSynchronizer.Wait();
285+
RunOnUIThread.Execute(() =>
286+
{
287+
repeater = new ItemsRepeater() {
288+
ItemsSource = items,
289+
ItemTemplate = CreateDataTemplateWithContent(@"<Button Content='{Binding}'/>"),
290+
Layout = layout
291+
};
292+
Content = repeater;
293+
});
295294

296-
RunOnUIThread.Execute(() =>
297-
{
298-
Log.Comment("Removing focused element from collection");
299-
items.Remove(targetItem);
295+
IdleSynchronizer.Wait();
300296

301-
Log.Comment("Reset the collection with an empty list");
302-
repeater.ItemsSource = new List<string>() ;
303-
});
297+
RunOnUIThread.Execute(() =>
298+
{
299+
Log.Comment("Setting Focus on item " + targetIndex);
300+
Button toFocus = (Button)repeater.TryGetElement(targetIndex);
301+
Verify.AreEqual(targetItem, toFocus.Content as string);
302+
toFocus.Focus(FocusState.Keyboard);
303+
});
304304

305-
IdleSynchronizer.Wait();
305+
IdleSynchronizer.Wait();
306306

307-
RunOnUIThread.Execute(() =>
308-
{
309-
Log.Comment("Verify new elements");
310-
for (int i = 0; i < items.Count; i++)
307+
RunOnUIThread.Execute(() =>
311308
{
312-
Button currentButton = (Button)repeater.TryGetElement(i);
313-
Verify.IsNull(currentButton);
314-
}
315-
});
309+
Log.Comment("Removing focused element from collection");
310+
items.Remove(targetItem);
311+
312+
Log.Comment("Reset the collection with an empty list");
313+
repeater.ItemsSource = new List<string>();
314+
});
315+
316+
IdleSynchronizer.Wait();
317+
318+
RunOnUIThread.Execute(() =>
319+
{
320+
Log.Comment("Verify new elements");
321+
for (int i = 0; i < items.Count; i++)
322+
{
323+
Button currentButton = (Button)repeater.TryGetElement(i);
324+
Verify.IsNull(currentButton);
325+
}
326+
});
327+
}
316328
}
317329

318330
private DataTemplate CreateDataTemplateWithContent(string content)

dev/Repeater/ItemsRepeater.cpp

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -516,26 +516,26 @@ void ItemsRepeater::OnDataSourcePropertyChanged(const winrt::ItemsSourceView& ol
516516
m_itemsSourceViewChanged = newValue.CollectionChanged(winrt::auto_revoke, { this, &ItemsRepeater::OnItemsSourceViewChanged });
517517
}
518518

519-
if (auto layout = Layout())
520-
{
521-
if (auto virtualLayout = layout.try_as<winrt::VirtualizingLayout>())
522-
{
523-
auto args = winrt::NotifyCollectionChangedEventArgs(
524-
winrt::NotifyCollectionChangedAction::Reset,
525-
nullptr /* newItems */,
526-
nullptr /* oldItems */,
527-
-1 /* newIndex */,
528-
-1 /* oldIndex */);
529-
args.Action();
530-
m_processingItemsSourceChange.set(args);
531-
auto processingChange = gsl::finally([this]()
532-
{
533-
m_processingItemsSourceChange.set(nullptr);
534-
});
519+
if (auto const layout = Layout())
520+
{
521+
auto const args = winrt::NotifyCollectionChangedEventArgs(
522+
winrt::NotifyCollectionChangedAction::Reset,
523+
nullptr /* newItems */,
524+
nullptr /* oldItems */,
525+
-1 /* newIndex */,
526+
-1 /* oldIndex */);
527+
args.Action();
528+
auto const processingChange = gsl::finally([this]()
529+
{
530+
m_processingItemsSourceChange.set(nullptr);
531+
});
532+
m_processingItemsSourceChange.set(args);
535533

534+
if (auto const virtualLayout = layout.try_as<winrt::VirtualizingLayout>())
535+
{
536536
virtualLayout.OnItemsChangedCore(GetLayoutContext(), newValue, args);
537537
}
538-
else if (auto nonVirtualLayout = layout.try_as<winrt::NonVirtualizingLayout>())
538+
else if (auto const nonVirtualLayout = layout.try_as<winrt::NonVirtualizingLayout>())
539539
{
540540
// Walk through all the elements and make sure they are cleared for
541541
// non-virtualizing layouts.
@@ -565,36 +565,34 @@ void ItemsRepeater::OnItemTemplateChanged(const winrt::IElementFactory& oldValue
565565
// have already been created and are now in the tree. The easiest way to do that
566566
// would be to do a reset.. Note that this has to be done before we change the template
567567
// so that the cleared elements go back into the old template.
568-
if (auto layout = Layout())
569-
{
570-
if (auto virtualLayout = layout.try_as<winrt::VirtualizingLayout>())
571-
{
572-
auto args = winrt::NotifyCollectionChangedEventArgs(
573-
winrt::NotifyCollectionChangedAction::Reset,
574-
nullptr /* newItems */,
575-
nullptr /* oldItems */,
576-
-1 /* newIndex */,
577-
-1 /* oldIndex */);
578-
args.Action();
579-
m_processingItemsSourceChange.set(args);
580-
auto processingChange = gsl::finally([this]()
581-
{
582-
m_processingItemsSourceChange.set(nullptr);
583-
});
568+
if (auto const layout = Layout())
569+
{
570+
auto const args = winrt::NotifyCollectionChangedEventArgs(
571+
winrt::NotifyCollectionChangedAction::Reset,
572+
nullptr /* newItems */,
573+
nullptr /* oldItems */,
574+
-1 /* newIndex */,
575+
-1 /* oldIndex */);
576+
args.Action();
577+
auto const processingChange = gsl::finally([this]()
578+
{
579+
m_processingItemsSourceChange.set(nullptr);
580+
});
581+
m_processingItemsSourceChange.set(args);
584582

583+
if (auto const virtualLayout = layout.try_as<winrt::VirtualizingLayout>())
584+
{
585585
virtualLayout.OnItemsChangedCore(GetLayoutContext(), newValue, args);
586586
}
587-
else if (auto nonVirtualLayout = layout.try_as<winrt::NonVirtualizingLayout>())
587+
else if (auto const nonVirtualLayout = layout.try_as<winrt::NonVirtualizingLayout>())
588588
{
589589
// Walk through all the elements and make sure they are cleared for
590590
// non-virtualizing layouts.
591-
auto children = Children();
592-
for (unsigned i = 0u; i < children.Size(); ++i)
591+
for (auto const& child : Children())
593592
{
594-
auto element = children.GetAt(i);
595-
if (GetVirtualizationInfo(element)->IsRealized())
593+
if (GetVirtualizationInfo(child)->IsRealized())
596594
{
597-
ClearElementImpl(element);
595+
ClearElementImpl(child);
598596
}
599597
}
600598
}

0 commit comments

Comments
 (0)