From 21574f5607d687c24d1c831bd808733d71650439 Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Fri, 3 Mar 2023 13:59:00 +0100 Subject: [PATCH] Expose pre/post collection changed events. Instead of implementing `ICollectionChangedListener` on `SelectionNodeBase`. We may want to expose this publicly at some point. --- src/Avalonia.Controls/ItemsSourceView.cs | 39 +++++++++++-------- .../Selection/SelectionNodeBase.cs | 38 +++++++++--------- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/src/Avalonia.Controls/ItemsSourceView.cs b/src/Avalonia.Controls/ItemsSourceView.cs index 1fa8f6a5cf..416b909219 100644 --- a/src/Avalonia.Controls/ItemsSourceView.cs +++ b/src/Avalonia.Controls/ItemsSourceView.cs @@ -27,6 +27,7 @@ namespace Avalonia.Controls private readonly IList _inner; private NotifyCollectionChangedEventHandler? _collectionChanged; + private NotifyCollectionChangedEventHandler? _preCollectionChanged; private NotifyCollectionChangedEventHandler? _postCollectionChanged; private bool _listening; @@ -70,7 +71,7 @@ namespace Avalonia.Controls /// Gets a value that indicates whether the items source can provide a unique key for each item. /// /// - /// TODO: Not yet implemented in Avalonia. + /// Not implemented in Avalonia, preserved here for ItemsRepeater's usage. /// internal bool HasKeyIndexMapping => false; @@ -92,6 +93,25 @@ namespace Avalonia.Controls } } + /// + /// Occurs when a collection has finished changing and all + /// event handlers have been notified. + /// + internal event NotifyCollectionChangedEventHandler? PreCollectionChanged + { + add + { + AddListenerIfNecessary(); + _preCollectionChanged += value; + } + + remove + { + _preCollectionChanged -= value; + RemoveListenerIfNecessary(); + } + } + /// /// Occurs when a collection has finished changing and all /// event handlers have been notified. @@ -229,6 +249,7 @@ namespace Avalonia.Controls void ICollectionChangedListener.PreChanged(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e) { + _preCollectionChanged?.Invoke(this, e); } void ICollectionChangedListener.Changed(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e) @@ -241,22 +262,6 @@ namespace Avalonia.Controls _postCollectionChanged?.Invoke(this, e); } - internal void AddListener(ICollectionChangedListener listener) - { - if (Inner is INotifyCollectionChanged incc) - { - CollectionChangedEventManager.Instance.AddListener(incc, listener); - } - } - - internal void RemoveListener(ICollectionChangedListener listener) - { - if (Inner is INotifyCollectionChanged incc) - { - CollectionChangedEventManager.Instance.RemoveListener(incc, listener); - } - } - /// /// Retrieves the index of the item that has the specified unique identifier (key). /// diff --git a/src/Avalonia.Controls/Selection/SelectionNodeBase.cs b/src/Avalonia.Controls/Selection/SelectionNodeBase.cs index 22db0cbb6c..caeff61f07 100644 --- a/src/Avalonia.Controls/Selection/SelectionNodeBase.cs +++ b/src/Avalonia.Controls/Selection/SelectionNodeBase.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; -using Avalonia.Controls.Utils; namespace Avalonia.Controls.Selection { @@ -10,7 +9,7 @@ namespace Avalonia.Controls.Selection /// Base class for selection models. /// /// The type of the element being selected. - public abstract class SelectionNodeBase : ICollectionChangedListener + public abstract class SelectionNodeBase { private IEnumerable? _source; private bool _rangesEnabled; @@ -24,12 +23,28 @@ namespace Avalonia.Controls.Selection get => _source; set { + void OnPreChanged(object? sender, NotifyCollectionChangedEventArgs e) => OnSourceCollectionChangeStarted(); + void OnChanged(object? sender, NotifyCollectionChangedEventArgs e) => OnSourceCollectionChanged(e); + void OnPostChanged(object? sender, NotifyCollectionChangedEventArgs e) => OnSourceCollectionChangeFinished(); + if (_source != value) { - ItemsView?.RemoveListener(this); + if (ItemsView is not null) + { + ItemsView.PreCollectionChanged -= OnPreChanged; + ItemsView.CollectionChanged -= OnChanged; + ItemsView.PostCollectionChanged -= OnPostChanged; + } + _source = value; ItemsView = value is not null ? ItemsSourceView.GetOrCreate(value) : null; - ItemsView?.AddListener(this); + + if (ItemsView is not null) + { + ItemsView.PreCollectionChanged += OnPreChanged; + ItemsView.CollectionChanged += OnChanged; + ItemsView.PostCollectionChanged += OnPostChanged; + } } } } @@ -73,21 +88,6 @@ namespace Avalonia.Controls.Selection } } - void ICollectionChangedListener.PreChanged(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e) - { - OnSourceCollectionChangeStarted(); - } - - void ICollectionChangedListener.Changed(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e) - { - OnSourceCollectionChanged(e); - } - - void ICollectionChangedListener.PostChanged(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e) - { - OnSourceCollectionChangeFinished(); - } - /// /// Called when the source collection starts changing. ///