Browse Source

Make AvaloniaPropertyObservable use weak refs.

And remove `WeakPropertyChangedObservable`/`GetWeakObservable`.
pull/1690/head
Steven Kirk 8 years ago
committed by Steven Kirk
parent
commit
34474af835
  1. 23
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  2. 2
      src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
  3. 17
      src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs
  4. 85
      src/Avalonia.Base/Reactive/WeakPropertyChangedObservable.cs

23
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@ -36,6 +36,9 @@ namespace Avalonia
/// An observable which fires immediately with the current value of the property on the
/// object and subsequently each time the property value changes.
/// </returns>
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<object> GetObservable(this IAvaloniaObject o, AvaloniaProperty property)
{
Contract.Requires<ArgumentNullException>(o != null);
@ -54,6 +57,9 @@ namespace Avalonia
/// An observable which fires immediately with the current value of the property on the
/// object and subsequently each time the property value changes.
/// </returns>
/// <remarks>
/// The subscription to <paramref name="o"/> is created using a weak reference.
/// </remarks>
public static IObservable<T> GetObservable<T>(this IAvaloniaObject o, AvaloniaProperty<T> property)
{
Contract.Requires<ArgumentNullException>(o != null);
@ -130,23 +136,6 @@ namespace Avalonia
o.GetObservable(property));
}
/// <summary>
/// Gets a weak observable for a <see cref="AvaloniaProperty"/>.
/// </summary>
/// <param name="o">The object.</param>
/// <param name="property">The property.</param>
/// <returns>An observable.</returns>
public static IObservable<object> GetWeakObservable(this IAvaloniaObject o, AvaloniaProperty property)
{
Contract.Requires<ArgumentNullException>(o != null);
Contract.Requires<ArgumentNullException>(property != null);
return new WeakPropertyChangedObservable(
new WeakReference<IAvaloniaObject>(o),
property,
GetDescription(o, property));
}
/// <summary>
/// Binds a property on an <see cref="IAvaloniaObject"/> to an <see cref="IBinding"/>.
/// </summary>

2
src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs

@ -153,7 +153,7 @@ namespace Avalonia.Data.Core.Plugins
protected override void SubscribeCore(IObserver<object> observer)
{
_subscription = Instance?.GetWeakObservable(_property).Subscribe(observer);
_subscription = Instance?.GetObservable(_property).Subscribe(observer);
}
}
}

17
src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs

@ -1,10 +1,11 @@
using System;
using Avalonia.Utilities;
namespace Avalonia.Reactive
{
public class AvaloniaPropertyObservable<T> : LightweightObservableBase<T>, IDescription
{
private readonly IAvaloniaObject _target;
private readonly WeakReference<IAvaloniaObject> _target;
private readonly AvaloniaProperty _property;
private T _value;
@ -12,7 +13,7 @@ namespace Avalonia.Reactive
IAvaloniaObject target,
AvaloniaProperty property)
{
_target = target;
_target = new WeakReference<IAvaloniaObject>(target);
_property = property;
}
@ -20,13 +21,19 @@ namespace Avalonia.Reactive
protected override void Initialize()
{
_value = (T)_target.GetValue(_property);
_target.PropertyChanged += PropertyChanged;
if (_target.TryGetTarget(out var target))
{
_value = (T)target.GetValue(_property);
target.PropertyChanged += PropertyChanged;
}
}
protected override void Deinitialize()
{
_target.PropertyChanged -= PropertyChanged;
if (_target.TryGetTarget(out var target))
{
target.PropertyChanged -= PropertyChanged;
}
}
protected override void Subscribed(IObserver<T> observer, bool first)

85
src/Avalonia.Base/Reactive/WeakPropertyChangedObservable.cs

@ -1,85 +0,0 @@
// 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.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using Avalonia.Utilities;
namespace Avalonia.Reactive
{
internal class WeakPropertyChangedObservable : ObservableBase<object>,
IWeakSubscriber<AvaloniaPropertyChangedEventArgs>, IDescription
{
private WeakReference<IAvaloniaObject> _sourceReference;
private readonly AvaloniaProperty _property;
private readonly Subject<object> _changed = new Subject<object>();
private int _count;
public WeakPropertyChangedObservable(
WeakReference<IAvaloniaObject> source,
AvaloniaProperty property,
string description)
{
_sourceReference = source;
_property = property;
Description = description;
}
public string Description { get; }
public void OnEvent(object sender, AvaloniaPropertyChangedEventArgs e)
{
if (e.Property == _property)
{
_changed.OnNext(e.NewValue);
}
}
protected override IDisposable SubscribeCore(IObserver<object> observer)
{
IAvaloniaObject instance;
if (_sourceReference.TryGetTarget(out instance))
{
if (_count++ == 0)
{
WeakSubscriptionManager.Subscribe(
instance,
nameof(instance.PropertyChanged),
this);
}
observer.OnNext(instance.GetValue(_property));
return Observable.Using(() => Disposable.Create(DecrementCount), _ => _changed)
.Subscribe(observer);
}
else
{
_changed.OnCompleted();
observer.OnCompleted();
return Disposable.Empty;
}
}
private void DecrementCount()
{
if (--_count == 0)
{
IAvaloniaObject instance;
if (_sourceReference.TryGetTarget(out instance))
{
WeakSubscriptionManager.Unsubscribe(
instance,
nameof(instance.PropertyChanged),
this);
}
}
}
}
}
Loading…
Cancel
Save