NotifyCollectionChangedExtensions.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Collections.Specialized;
  5. using System.Reactive.Linq;
  6. using Avalonia.Reactive;
  7. using Avalonia.Utilities;
  8. namespace Avalonia.Collections
  9. {
  10. public static class NotifyCollectionChangedExtensions
  11. {
  12. /// <summary>
  13. /// Gets a weak observable for the CollectionChanged event.
  14. /// </summary>
  15. /// <param name="collection">The collection.</param>
  16. /// <returns>An observable.</returns>
  17. public static IObservable<NotifyCollectionChangedEventArgs> GetWeakCollectionChangedObservable(
  18. this INotifyCollectionChanged collection)
  19. {
  20. Contract.Requires<ArgumentNullException>(collection != null);
  21. return new WeakCollectionChangedObservable(new WeakReference<INotifyCollectionChanged>(collection));
  22. }
  23. /// <summary>
  24. /// Subscribes to the CollectionChanged event using a weak subscription.
  25. /// </summary>
  26. /// <param name="collection">The collection.</param>
  27. /// <param name="handler">
  28. /// An action called when the collection event is raised.
  29. /// </param>
  30. /// <returns>A disposable used to terminate the subscription.</returns>
  31. public static IDisposable WeakSubscribe(
  32. this INotifyCollectionChanged collection,
  33. NotifyCollectionChangedEventHandler handler)
  34. {
  35. Contract.Requires<ArgumentNullException>(collection != null);
  36. Contract.Requires<ArgumentNullException>(handler != null);
  37. return collection.GetWeakCollectionChangedObservable()
  38. .Subscribe(e => handler(collection, e));
  39. }
  40. /// <summary>
  41. /// Subscribes to the CollectionChanged event using a weak subscription.
  42. /// </summary>
  43. /// <param name="collection">The collection.</param>
  44. /// <param name="handler">
  45. /// An action called when the collection event is raised.
  46. /// </param>
  47. /// <returns>A disposable used to terminate the subscription.</returns>
  48. public static IDisposable WeakSubscribe(
  49. this INotifyCollectionChanged collection,
  50. Action<NotifyCollectionChangedEventArgs> handler)
  51. {
  52. Contract.Requires<ArgumentNullException>(collection != null);
  53. Contract.Requires<ArgumentNullException>(handler != null);
  54. return collection.GetWeakCollectionChangedObservable().Subscribe(handler);
  55. }
  56. private class WeakCollectionChangedObservable : LightweightObservableBase<NotifyCollectionChangedEventArgs>,
  57. IWeakSubscriber<NotifyCollectionChangedEventArgs>
  58. {
  59. private WeakReference<INotifyCollectionChanged> _sourceReference;
  60. public WeakCollectionChangedObservable(WeakReference<INotifyCollectionChanged> source)
  61. {
  62. _sourceReference = source;
  63. }
  64. public void OnEvent(object sender, NotifyCollectionChangedEventArgs e)
  65. {
  66. PublishNext(e);
  67. }
  68. protected override void Initialize()
  69. {
  70. if (_sourceReference.TryGetTarget(out INotifyCollectionChanged instance))
  71. {
  72. WeakSubscriptionManager.Subscribe(
  73. instance,
  74. nameof(instance.CollectionChanged),
  75. this);
  76. }
  77. }
  78. protected override void Deinitialize()
  79. {
  80. if (_sourceReference.TryGetTarget(out INotifyCollectionChanged instance))
  81. {
  82. WeakSubscriptionManager.Unsubscribe(
  83. instance,
  84. nameof(instance.CollectionChanged),
  85. this);
  86. }
  87. }
  88. }
  89. }
  90. }