From 7f722305978c17fdd1d9a879e5148cbb55ad4709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Komosi=C5=84ski?= Date: Tue, 12 Nov 2019 14:40:34 +0100 Subject: [PATCH] Fix ItemsRepeater not clearing focused elements on items source changed. --- .../Pages/ItemsRepeaterPage.xaml | 3 +- .../Pages/ItemsRepeaterPage.xaml.cs | 9 +++++ .../ViewModels/ItemsRepeaterPageViewModel.cs | 36 ++++++++++++++----- .../Repeater/ItemsRepeater.cs | 12 ++++++- 4 files changed, 50 insertions(+), 10 deletions(-) diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml index 103c016298f..028a2944925 100644 --- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml +++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml @@ -15,6 +15,7 @@ + - + diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs index decd849adcb..6fa9fc515ee 100644 --- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs +++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs @@ -20,6 +20,7 @@ public ItemsRepeaterPage() _repeater = this.FindControl("repeater"); _scroller = this.FindControl("scroller"); _repeater.PointerPressed += RepeaterClick; + _repeater.KeyDown += RepeaterOnKeyDown; DataContext = new ItemsRepeaterPageViewModel(); } @@ -77,5 +78,13 @@ private void RepeaterClick(object sender, PointerPressedEventArgs e) var item = (e.Source as TextBlock)?.DataContext as ItemsRepeaterPageViewModel.Item; ((ItemsRepeaterPageViewModel)DataContext).SelectedItem = item; } + + private void RepeaterOnKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.F5) + { + ((ItemsRepeaterPageViewModel)DataContext).ResetItems(); + } + } } } diff --git a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs index bc2ce807148..de5669123fa 100644 --- a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs +++ b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs @@ -7,25 +7,27 @@ namespace ControlCatalog.ViewModels { public class ItemsRepeaterPageViewModel : ReactiveObject { - private int newItemIndex = 1; + private int _newItemIndex = 1; + private int _newGenerationIndex = 0; + private ObservableCollection _items; public ItemsRepeaterPageViewModel() { - Items = new ObservableCollection( - Enumerable.Range(1, 100000).Select(i => new Item - { - Text = $"Item {i.ToString()}", - })); + Items = CreateItems(); } - public ObservableCollection Items { get; } + public ObservableCollection Items + { + get => _items; + set => this.RaiseAndSetIfChanged(ref _items, value); + } public Item SelectedItem { get; set; } public void AddItem() { var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1; - Items.Insert(index + 1, new Item { Text = $"New Item {newItemIndex++}" }); + Items.Insert(index + 1, new Item { Text = $"New Item {_newItemIndex++}" }); } public void RandomizeHeights() @@ -38,6 +40,24 @@ public void RandomizeHeights() } } + public void ResetItems() + { + Items = CreateItems(); + } + + private ObservableCollection CreateItems() + { + var suffix = _newGenerationIndex == 0 ? string.Empty : $"[{_newGenerationIndex.ToString()}]"; + + _newGenerationIndex++; + + return new ObservableCollection( + Enumerable.Range(1, 100000).Select(i => new Item + { + Text = $"Item {i.ToString()} {suffix}" + })); + } + public class Item : ReactiveObject { private double _height = double.NaN; diff --git a/src/Avalonia.Controls/Repeater/ItemsRepeater.cs b/src/Avalonia.Controls/Repeater/ItemsRepeater.cs index 257c1b23994..0e2136a6f3b 100644 --- a/src/Avalonia.Controls/Repeater/ItemsRepeater.cs +++ b/src/Avalonia.Controls/Repeater/ItemsRepeater.cs @@ -565,7 +565,17 @@ private void OnDataSourcePropertyChanged(ItemsSourceView oldValue, ItemsSourceVi if (Layout is VirtualizingLayout virtualLayout) { var args = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); - virtualLayout.OnItemsChanged(GetLayoutContext(), newValue, args); + + _processingItemsSourceChange = args; + + try + { + virtualLayout.OnItemsChanged(GetLayoutContext(), newValue, args); + } + finally + { + _processingItemsSourceChange = null; + } } else if (Layout is NonVirtualizingLayout nonVirtualLayout) {