committed by
GitHub
3 changed files with 153 additions and 12 deletions
@ -0,0 +1,127 @@ |
|||||
|
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
|
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Specialized; |
||||
|
using System.Reactive; |
||||
|
using System.Reactive.Disposables; |
||||
|
using System.Reactive.Linq; |
||||
|
using System.Reactive.Subjects; |
||||
|
using Avalonia.Utilities; |
||||
|
|
||||
|
namespace Avalonia.Collections |
||||
|
{ |
||||
|
public static class NotifyCollectionChangedExtensions |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Gets a weak observable for the CollectionChanged event.
|
||||
|
/// </summary>
|
||||
|
/// <param name="collection">The collection.</param>
|
||||
|
/// <returns>An observable.</returns>
|
||||
|
public static IObservable<NotifyCollectionChangedEventArgs> GetWeakCollectionChangedObservable( |
||||
|
this INotifyCollectionChanged collection) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(collection != null); |
||||
|
|
||||
|
return new WeakCollectionChangedObservable(new WeakReference<INotifyCollectionChanged>(collection)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Subcribes to the CollectionChanged event using a weak subscription.
|
||||
|
/// </summary>
|
||||
|
/// <param name="collection">The collection.</param>
|
||||
|
/// <param name="handler">
|
||||
|
/// An action called when the collection event is raised.
|
||||
|
/// </param>
|
||||
|
/// <returns>A disposable used to terminate the subscription.</returns>
|
||||
|
public static IDisposable WeakSubscribe( |
||||
|
this INotifyCollectionChanged collection, |
||||
|
NotifyCollectionChangedEventHandler handler) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(collection != null); |
||||
|
Contract.Requires<ArgumentNullException>(handler != null); |
||||
|
|
||||
|
return |
||||
|
collection.GetWeakCollectionChangedObservable() |
||||
|
.Subscribe(e => handler.Invoke(collection, e)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Subcribes to the CollectionChanged event using a weak subscription.
|
||||
|
/// </summary>
|
||||
|
/// <param name="collection">The collection.</param>
|
||||
|
/// <param name="handler">
|
||||
|
/// An action called when the collection event is raised.
|
||||
|
/// </param>
|
||||
|
/// <returns>A disposable used to terminate the subscription.</returns>
|
||||
|
public static IDisposable WeakSubscribe( |
||||
|
this INotifyCollectionChanged collection, |
||||
|
Action<NotifyCollectionChangedEventArgs> handler) |
||||
|
{ |
||||
|
Contract.Requires<ArgumentNullException>(collection != null); |
||||
|
Contract.Requires<ArgumentNullException>(handler != null); |
||||
|
|
||||
|
return |
||||
|
collection.GetWeakCollectionChangedObservable() |
||||
|
.Subscribe(handler); |
||||
|
} |
||||
|
|
||||
|
private class WeakCollectionChangedObservable : ObservableBase<NotifyCollectionChangedEventArgs>, |
||||
|
IWeakSubscriber<NotifyCollectionChangedEventArgs> |
||||
|
{ |
||||
|
private WeakReference<INotifyCollectionChanged> _sourceReference; |
||||
|
private readonly Subject<NotifyCollectionChangedEventArgs> _changed = new Subject<NotifyCollectionChangedEventArgs>(); |
||||
|
|
||||
|
private int _count; |
||||
|
|
||||
|
public WeakCollectionChangedObservable(WeakReference<INotifyCollectionChanged> source) |
||||
|
{ |
||||
|
_sourceReference = source; |
||||
|
} |
||||
|
|
||||
|
public void OnEvent(object sender, NotifyCollectionChangedEventArgs e) |
||||
|
{ |
||||
|
_changed.OnNext(e); |
||||
|
} |
||||
|
|
||||
|
protected override IDisposable SubscribeCore(IObserver<NotifyCollectionChangedEventArgs> observer) |
||||
|
{ |
||||
|
if (_sourceReference.TryGetTarget(out INotifyCollectionChanged instance)) |
||||
|
{ |
||||
|
if (_count++ == 0) |
||||
|
{ |
||||
|
WeakSubscriptionManager.Subscribe( |
||||
|
instance, |
||||
|
nameof(instance.CollectionChanged), |
||||
|
this); |
||||
|
} |
||||
|
|
||||
|
return Observable.Using(() => Disposable.Create(DecrementCount), _ => _changed) |
||||
|
.Subscribe(observer); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
_changed.OnCompleted(); |
||||
|
observer.OnCompleted(); |
||||
|
return Disposable.Empty; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void DecrementCount() |
||||
|
{ |
||||
|
if (--_count == 0) |
||||
|
{ |
||||
|
if (_sourceReference.TryGetTarget(out INotifyCollectionChanged instance)) |
||||
|
{ |
||||
|
WeakSubscriptionManager.Unsubscribe( |
||||
|
instance, |
||||
|
nameof(instance.CollectionChanged), |
||||
|
this); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue