csharpc-sharpdotnetxamlavaloniauicross-platformcross-platform-xamlavaloniaguimulti-platformuser-interfacedotnetcore
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
127 lines
4.8 KiB
127 lines
4.8 KiB
// 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|