From 40b73a661fc976c465ebca629a1f544ea0b5e6de Mon Sep 17 00:00:00 2001 From: lnxon <118665938+lnxon@users.noreply.github.com> Date: Tue, 21 Nov 2023 08:25:34 +0900 Subject: [PATCH] =?UTF-8?q?Fix=20issue=20#11006=20by=20correcting=20Select?= =?UTF-8?q?ionChanged=20event=20to=20be=20fired=20AFTER=20(not=20before)?= =?UTF-8?q?=20raising=20Prop=E2=80=A6=20(#13503)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix selectedchanged event to be fired AFTER (not before) raising Property changed notification * Unit test added --- .../Selection/SelectionModel.cs | 62 ++++++++++--------- .../Primitives/SelectingItemsControlTests.cs | 50 +++++++++++++++ 2 files changed, 82 insertions(+), 30 deletions(-) diff --git a/src/Avalonia.Controls/Selection/SelectionModel.cs b/src/Avalonia.Controls/Selection/SelectionModel.cs index 69bed2550e..5402499fcf 100644 --- a/src/Avalonia.Controls/Selection/SelectionModel.cs +++ b/src/Avalonia.Controls/Selection/SelectionModel.cs @@ -674,7 +674,39 @@ namespace Avalonia.Controls.Selection indexesChanged |= CommitDeselect(range.Begin, range.End) > 0; } } + + + + if (raisePropertyChanged) + { + if (oldSelectedIndex != _selectedIndex) + { + indexesChanged = true; + RaisePropertyChanged(nameof(SelectedIndex)); + } + + if (oldSelectedIndex != _selectedIndex || operation.IsSourceUpdate) + { + RaisePropertyChanged(nameof(SelectedItem)); + } + if (oldAnchorIndex != _anchorIndex) + { + indexesChanged = true; + RaisePropertyChanged(nameof(AnchorIndex)); + } + + if (indexesChanged) + { + RaisePropertyChanged(nameof(SelectedIndexes)); + } + + if (indexesChanged || operation.IsSourceUpdate) + { + RaisePropertyChanged(nameof(SelectedItems)); + } + } + if (SelectionChanged is not null || _untypedSelectionChanged is not null) { IReadOnlyList? deselected = operation.DeselectedRanges; @@ -715,36 +747,6 @@ namespace Avalonia.Controls.Selection _untypedSelectionChanged?.Invoke(this, e); } } - - if (raisePropertyChanged) - { - if (oldSelectedIndex != _selectedIndex) - { - indexesChanged = true; - RaisePropertyChanged(nameof(SelectedIndex)); - } - - if (oldSelectedIndex != _selectedIndex || operation.IsSourceUpdate) - { - RaisePropertyChanged(nameof(SelectedItem)); - } - - if (oldAnchorIndex != _anchorIndex) - { - indexesChanged = true; - RaisePropertyChanged(nameof(AnchorIndex)); - } - - if (indexesChanged) - { - RaisePropertyChanged(nameof(SelectedIndexes)); - } - - if (indexesChanged || operation.IsSourceUpdate) - { - RaisePropertyChanged(nameof(SelectedItems)); - } - } } finally { diff --git a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs index d7e55ba95c..b8cd68d12f 100644 --- a/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs +++ b/tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -2224,6 +2224,56 @@ namespace Avalonia.Controls.UnitTests.Primitives Assert.Equal(0, selectedItemChangedRaised); } + + [Fact] + public void Should_First_Raise_Property_Changed_Notification_Then_Fire_Selection_Changed_Event() + { + using var _ = UnitTestApplication.Start(TestServices.MockPlatformRenderInterface); + + // Issue #11006 + var items = new ObservableCollection(); + + var vm = new SelectionViewModel + { + SelectedItem = "" , + }; + + var theListBox = new ListBox + { + DataContext = vm, + Template = Template(), + ItemsSource = items, + SelectionMode = SelectionMode.AlwaysSelected, + [!ListBox.SelectedItemProperty] = new Binding("SelectedItem"), + }; + + var target = new TextBox + { + Text = "", + }; + + Prepare(theListBox); + + items.Add("Default"); + items.Add("First"); + items.Add("Second"); + items.Add("Third"); + + theListBox.SelectionChanged += (s, e) => + { + target.Text = (string)vm.SelectedItem; + }; + + theListBox.SelectedIndex = 1; + Assert.Equal("First", target.Text); + + theListBox.SelectedIndex = 2; + Assert.Equal("Second", target.Text); + + theListBox.SelectedIndex = 3; + Assert.Equal("Third", target.Text); + + } private static IDisposable Start() {