| File: Internals\WeakEventProxy.cs | Web Access |
| Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls) |
using System; using System.Collections.Specialized; using System.ComponentModel; // NOTE: warning disabled for netstandard projects #pragma warning disable 0436 using MaybeNullWhenAttribute = System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute; #pragma warning restore 0436 namespace Microsoft.Maui.Controls { /// <summary> /// An abstract base class for subscribing to an event via WeakReference. /// See WeakNotifyCollectionChangedProxy below for sublcass usage. /// </summary> /// <typeparam name="TSource">The object type that has the event</typeparam> /// <typeparam name="TEventHandler">The event handler type of the event</typeparam> abstract class WeakEventProxy<TSource, TEventHandler> where TSource : class where TEventHandler : Delegate { WeakReference<TSource>? _source; WeakReference<TEventHandler>? _handler; public bool TryGetSource([MaybeNullWhen(false)] out TSource source) { if (_source is not null && _source.TryGetTarget(out source)) { return source is not null; } source = default; return false; } public bool TryGetHandler([MaybeNullWhen(false)] out TEventHandler handler) { if (_handler is not null && _handler.TryGetTarget(out handler)) { return handler is not null; } handler = default; return false; } public virtual void Subscribe(TSource source, TEventHandler handler) { _source = new WeakReference<TSource>(source); _handler = new WeakReference<TEventHandler>(handler); } public virtual void Unsubscribe() { _source = null; _handler = null; } } /// <summary> /// A "proxy" class for subscribing INotifyCollectionChanged via WeakReference. /// General usage is to store this in a member variable and call Subscribe()/Unsubscribe() appropriately. /// Your class should have a finalizer that calls Unsubscribe() to prevent WeakNotifyCollectionChangedProxy objects from leaking. /// </summary> class WeakNotifyCollectionChangedProxy : WeakEventProxy<INotifyCollectionChanged, NotifyCollectionChangedEventHandler> { public WeakNotifyCollectionChangedProxy() { } public WeakNotifyCollectionChangedProxy(INotifyCollectionChanged source, NotifyCollectionChangedEventHandler handler) { Subscribe(source, handler); } void OnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e) { if (TryGetHandler(out var handler)) { handler(sender, e); } else { Unsubscribe(); } } public override void Subscribe(INotifyCollectionChanged source, NotifyCollectionChangedEventHandler handler) { if (TryGetSource(out var s)) { s.CollectionChanged -= OnCollectionChanged; } source.CollectionChanged += OnCollectionChanged; base.Subscribe(source, handler); } public override void Unsubscribe() { if (TryGetSource(out var s)) { s.CollectionChanged -= OnCollectionChanged; } base.Unsubscribe(); } } /// <summary> /// A "proxy" class for subscribing INotifyPropertyChanged via WeakReference. /// General usage is to store this in a member variable and call Subscribe()/Unsubscribe() appropriately. /// Your class should have a finalizer that calls Unsubscribe() to prevent WeakNotifyPropertyChangedProxy objects from leaking. /// </summary> class WeakNotifyPropertyChangedProxy : WeakEventProxy<INotifyPropertyChanged, PropertyChangedEventHandler> { public WeakNotifyPropertyChangedProxy() { } public WeakNotifyPropertyChangedProxy(INotifyPropertyChanged source, PropertyChangedEventHandler handler) { Subscribe(source, handler); } void OnPropertyChanged(object? sender, PropertyChangedEventArgs e) { if (TryGetHandler(out var handler)) { handler(sender, e); } else { Unsubscribe(); } } public override void Subscribe(INotifyPropertyChanged source, PropertyChangedEventHandler handler) { if (TryGetSource(out var s)) { s.PropertyChanged -= OnPropertyChanged; } source.PropertyChanged += OnPropertyChanged; base.Subscribe(source, handler); } public override void Unsubscribe() { if (TryGetSource(out var s)) { s.PropertyChanged -= OnPropertyChanged; } base.Unsubscribe(); } } }