@ -17,12 +17,12 @@ namespace Avalonia.Controls.Utils
void PostChanged ( INotifyCollectionChanged sender , NotifyCollectionChangedEventArgs e ) ;
}
internal class CollectionChangedEventManager : IWeakSubscriber < NotifyCollectionChangedEventArgs >
internal class CollectionChangedEventManager
{
public static CollectionChangedEventManager Instance { get ; } = new CollectionChangedEventManager ( ) ;
private ConditionalWeakTable < INotifyCollectionChanged , List < WeakReference < ICollectionChangedListener > > > _ entries =
new ConditionalWeakTable < INotifyCollectionChanged , List < WeakReference < ICollectionChangedListener > > > ( ) ;
private ConditionalWeakTable < INotifyCollectionChanged , Entry > _ entries =
new ConditionalWeakTable < INotifyCollectionChanged , Entry > ( ) ;
private CollectionChangedEventManager ( )
{
@ -34,17 +34,13 @@ namespace Avalonia.Controls.Utils
listener = listener ? ? throw new ArgumentNullException ( nameof ( listener ) ) ;
Dispatcher . UIThread . VerifyAccess ( ) ;
if ( ! _ entries . TryGetValue ( collection , out var listeners ) )
if ( ! _ entries . TryGetValue ( collection , out var entry ) )
{
listeners = new List < WeakReference < ICollectionChangedListener > > ( ) ;
_ entries . Add ( collection , listeners ) ;
WeakSubscriptionManager . Subscribe (
collection ,
nameof ( INotifyCollectionChanged . CollectionChanged ) ,
this ) ;
entry = new Entry ( collection ) ;
_ entries . Add ( collection , entry ) ;
}
foreach ( var l in l isteners)
foreach ( var l in entry . Listeners )
{
if ( l . TryGetTarget ( out var target ) & & target = = listener )
{
@ -53,7 +49,7 @@ namespace Avalonia.Controls.Utils
}
}
l isteners. Add ( new WeakReference < ICollectionChangedListener > ( listener ) ) ;
entry . L isteners. Add ( new WeakReference < ICollectionChangedListener > ( listener ) ) ;
}
public void RemoveListener ( INotifyCollectionChanged collection , ICollectionChangedListener listener )
@ -62,8 +58,10 @@ namespace Avalonia.Controls.Utils
listener = listener ? ? throw new ArgumentNullException ( nameof ( listener ) ) ;
Dispatcher . UIThread . VerifyAccess ( ) ;
if ( _ entries . TryGetValue ( collection , out var listeners ) )
if ( _ entries . TryGetValue ( collection , out var entry ) )
{
var listeners = entry . Listeners ;
for ( var i = 0 ; i < listeners . Count ; + + i )
{
if ( listeners [ i ] . TryGetTarget ( out var target ) & & target = = listener )
@ -72,10 +70,7 @@ namespace Avalonia.Controls.Utils
if ( listeners . Count = = 0 )
{
WeakSubscriptionManager . Unsubscribe (
collection ,
nameof ( INotifyCollectionChanged . CollectionChanged ) ,
this ) ;
entry . Dispose ( ) ;
_ entries . Remove ( collection ) ;
}
@ -88,51 +83,72 @@ namespace Avalonia.Controls.Utils
"Collection listener not registered for this collection/listener combination." ) ;
}
void IWeakSubscriber < NotifyCollectionChangedEventArgs > . OnEvent ( object sender , NotifyCollectionChangedEventArgs e )
private class Entry : IWeakSubscriber < NotifyCollectionChangedEventArgs > , IDisposable
{
static void Notify (
INotifyCollectionChanged incc ,
NotifyCollectionChangedEventArgs args ,
List < WeakReference < ICollectionChangedListener > > listeners )
private INotifyCollectionChanged _ collection ;
public Entry ( INotifyCollectionChanged collection )
{
foreach ( var l in listeners )
_ collection = collection ;
Listeners = new List < WeakReference < ICollectionChangedListener > > ( ) ;
WeakSubscriptionManager . Subscribe (
_ collection ,
nameof ( INotifyCollectionChanged . CollectionChanged ) ,
this ) ;
}
public List < WeakReference < ICollectionChangedListener > > Listeners { get ; }
public void Dispose ( )
{
WeakSubscriptionManager . Unsubscribe (
_ collection ,
nameof ( INotifyCollectionChanged . CollectionChanged ) ,
this ) ;
}
void IWeakSubscriber < NotifyCollectionChangedEventArgs > . OnEvent ( object sender , NotifyCollectionChangedEventArgs e )
{
static void Notify (
INotifyCollectionChanged incc ,
NotifyCollectionChangedEventArgs args ,
List < WeakReference < ICollectionChangedListener > > listeners )
{
if ( l . TryGetTarget ( out var target ) )
foreach ( var l in listeners )
{
target . PreChanged ( incc , args ) ;
if ( l . TryGetTarget ( out var target ) )
{
target . PreChanged ( incc , args ) ;
}
}
}
foreach ( var l in listeners )
{
if ( l . TryGetTarget ( out var target ) )
foreach ( var l in listeners )
{
target . Changed ( incc , args ) ;
if ( l . TryGetTarget ( out var target ) )
{
target . Changed ( incc , args ) ;
}
}
}
foreach ( var l in listeners )
{
if ( l . TryGetTarget ( out var target ) )
foreach ( var l in listeners )
{
target . PostChanged ( incc , args ) ;
if ( l . TryGetTarget ( out var target ) )
{
target . PostChanged ( incc , args ) ;
}
}
}
}
if ( sender is INotifyCollectionChanged incc & & _ entries . TryGetValue ( incc , out var listeners ) )
{
var l = listeners . ToList ( ) ;
var l = Listeners . ToList ( ) ;
if ( Dispatcher . UIThread . CheckAccess ( ) )
{
Notify ( incc , e , l ) ;
Notify ( _ collection , e , l ) ;
}
else
{
var inccCapture = incc ;
var eCapture = e ;
Dispatcher . UIThread . Post ( ( ) = > Notify ( inccCapture , eCapture , l ) ) ;
Dispatcher . UIThread . Post ( ( ) = > Notify ( _ collection , eCapture , l ) ) ;
}
}
}