diff --git a/src/Avalonia.Styling/Styling/ActivatedObservable.cs b/src/Avalonia.Styling/Styling/ActivatedObservable.cs
index 3c58bb5f9d..4933daed31 100644
--- a/src/Avalonia.Styling/Styling/ActivatedObservable.cs
+++ b/src/Avalonia.Styling/Styling/ActivatedObservable.cs
@@ -2,8 +2,6 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
-using System.Collections.Generic;
-using System.Reactive.Disposables;
namespace Avalonia.Styling
{
@@ -17,14 +15,9 @@ namespace Avalonia.Styling
/// value. When the activator produces false it will produce
/// .
///
- internal class ActivatedObservable : IObservable, IDescription
+ internal class ActivatedObservable : ActivatedValue, IDescription
{
- private static readonly object NotSent = new object();
- private readonly Listener _listener;
- private List> _observers;
- private IDisposable _activatorSubscription;
private IDisposable _sourceSubscription;
- private object _last = NotSent;
///
/// Initializes a new instance of the class.
@@ -36,133 +29,49 @@ namespace Avalonia.Styling
IObservable activator,
IObservable source,
string description)
+ : base(activator, AvaloniaProperty.UnsetValue, description)
{
- Contract.Requires(activator != null);
Contract.Requires(source != null);
- Activator = activator;
- Description = description;
Source = source;
- _listener = new Listener(this);
}
- ///
- /// Gets the activator observable.
- ///
- public IObservable Activator { get; }
-
- ///
- /// Gets a description of the binding.
- ///
- public string Description { get; }
-
- ///
- /// Gets a value indicating whether the observable is active.
- ///
- public bool? IsActive { get; private set; }
-
///
/// Gets an observable which produces the .
///
public IObservable Source { get; }
- ///
- /// Gets the value that will be produced when is true.
- ///
- public object Value { get; private set; }
-
- public IDisposable Subscribe(IObserver observer)
- {
- var subscribe = _observers == null;
-
- _observers = _observers ?? new List>();
- _observers.Add(observer);
-
- if (subscribe)
- {
- _sourceSubscription = Source.Subscribe(_listener);
- _activatorSubscription = Activator.Subscribe(_listener);
- }
-
- return Disposable.Create(() =>
- {
- _observers.Remove(observer);
-
- if (_observers.Count == 0)
- {
- _activatorSubscription.Dispose();
- _sourceSubscription.Dispose();
- _activatorSubscription = null;
- _sourceSubscription = null;
- }
- });
- }
+ protected override ActivatorListener CreateListener() => new ValueListener(this);
- protected virtual void NotifyCompleted()
+ protected override void Deinitialize()
{
- foreach (var observer in _observers)
- {
- observer.OnCompleted();
- }
-
- _observers = null;
+ base.Deinitialize();
+ _sourceSubscription.Dispose();
+ _sourceSubscription = null;
}
- protected virtual void NotifyError(Exception error)
+ protected override void Initialize()
{
- foreach (var observer in _observers)
- {
- observer.OnError(error);
- }
-
- _observers = null;
+ base.Initialize();
+ _sourceSubscription = Source.Subscribe((ValueListener)Listener);
}
protected virtual void NotifyValue(object value)
{
Value = value;
- Update();
}
- protected virtual void NotifyActive(bool active)
+ private class ValueListener : ActivatorListener, IObserver
{
- IsActive = active;
- Update();
- }
-
- private void Update()
- {
- if (IsActive.HasValue)
- {
- var v = IsActive.Value ? Value : AvaloniaProperty.UnsetValue;
-
- if (!Equals(v, _last))
- {
- foreach (var observer in _observers)
- {
- observer.OnNext(v);
- }
-
- _last = v;
- }
- }
- }
-
- private class Listener : IObserver, IObserver
- {
- private readonly ActivatedObservable _parent;
-
- public Listener(ActivatedObservable parent)
+ public ValueListener(ActivatedObservable parent)
+ : base(parent)
{
- _parent = parent;
}
+ protected new ActivatedObservable Parent => (ActivatedObservable)base.Parent;
- void IObserver.OnCompleted() => _parent.NotifyCompleted();
- void IObserver.OnCompleted() => _parent.NotifyCompleted();
- void IObserver.OnError(Exception error) => _parent.NotifyError(error);
- void IObserver.OnError(Exception error) => _parent.NotifyError(error);
- void IObserver.OnNext(bool value) => _parent.NotifyActive(value);
- void IObserver.OnNext(object value) => _parent.NotifyValue(value);
+ void IObserver.OnCompleted() => Parent.NotifyCompleted();
+ void IObserver.OnError(Exception error) => Parent.NotifyError(error);
+ void IObserver.OnNext(object value) => Parent.NotifyValue(value);
}
}
}
diff --git a/src/Avalonia.Styling/Styling/ActivatedValue.cs b/src/Avalonia.Styling/Styling/ActivatedValue.cs
index 3b9324c059..683121628c 100644
--- a/src/Avalonia.Styling/Styling/ActivatedValue.cs
+++ b/src/Avalonia.Styling/Styling/ActivatedValue.cs
@@ -2,8 +2,8 @@
// 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.Linq;
+using System.Collections.Generic;
+using System.Reactive.Disposables;
namespace Avalonia.Styling
{
@@ -16,12 +16,13 @@ namespace Avalonia.Styling
/// will produce the current value. When the activator
/// produces false it will produce .
///
- internal class ActivatedValue : ObservableBase, IDescription
+ internal class ActivatedValue : IObservable, IDescription
{
- ///
- /// The activator.
- ///
- private readonly IObservable _activator;
+ private static readonly object NotSent = new object();
+ private List> _observers = new List>();
+ private IDisposable _activatorSubscription;
+ private object _value;
+ private object _last = NotSent;
///
/// Initializes a new instance of the class.
@@ -34,39 +35,135 @@ namespace Avalonia.Styling
object value,
string description)
{
- _activator = activator;
+ Contract.Requires(activator != null);
+
+ Activator = activator;
Value = value;
Description = description;
+ Listener = CreateListener();
}
///
- /// Gets the activated value.
+ /// Gets the activator observable.
///
- public object Value
- {
- get;
- }
+ public IObservable Activator { get; }
///
/// Gets a description of the binding.
///
- public string Description
- {
- get;
- }
+ public string Description { get; }
+
+ ///
+ /// Gets a value indicating whether the activator is active.
+ ///
+ public bool? IsActive { get; private set; }
///
- /// Notifies the provider that an observer is to receive notifications.
+ /// Gets the value that will be produced when is true.
///
- /// The observer.
- /// IDisposable object used to unsubscribe from the observable sequence.
- protected override IDisposable SubscribeCore(IObserver observer)
+ public object Value
+ {
+ get => _value;
+ protected set
+ {
+ _value = value;
+ PublishValue();
+ }
+ }
+
+ protected ActivatorListener Listener { get; }
+
+ public virtual IDisposable Subscribe(IObserver observer)
+ {
+ _observers.Add(observer);
+
+ if (_observers.Count == 1)
+ {
+ Initialize();
+ }
+
+ return Disposable.Create(() =>
+ {
+ _observers.Remove(observer);
+
+ if (_observers.Count == 0)
+ {
+ Deinitialize();
+ }
+ });
+ }
+
+ protected virtual ActivatorListener CreateListener() => new ActivatorListener(this);
+
+ protected virtual void Deinitialize()
{
- Contract.Requires(observer != null);
+ _activatorSubscription.Dispose();
+ _activatorSubscription = null;
+ }
+
+ protected virtual void Initialize()
+ {
+ _activatorSubscription = Activator.Subscribe(Listener);
+ }
+
+ protected virtual void NotifyCompleted()
+ {
+ foreach (var observer in _observers)
+ {
+ observer.OnCompleted();
+ }
+
+ Deinitialize();
+ _observers = null;
+ }
+
+ protected virtual void NotifyError(Exception error)
+ {
+ foreach (var observer in _observers)
+ {
+ observer.OnError(error);
+ }
+
+ Deinitialize();
+ _observers = null;
+ }
+
+ protected virtual void NotifyActive(bool active)
+ {
+ IsActive = active;
+ PublishValue();
+ }
+
+ private void PublishValue()
+ {
+ if (IsActive.HasValue)
+ {
+ var v = IsActive.Value ? Value : AvaloniaProperty.UnsetValue;
+
+ if (!Equals(v, _last))
+ {
+ foreach (var observer in _observers)
+ {
+ observer.OnNext(v);
+ }
+
+ _last = v;
+ }
+ }
+ }
+
+ protected class ActivatorListener : IObserver
+ {
+ public ActivatorListener(ActivatedValue parent)
+ {
+ Parent = parent;
+ }
+
+ protected ActivatedValue Parent { get; }
- return _activator
- .Select(active => active ? Value : AvaloniaProperty.UnsetValue)
- .Subscribe(observer);
+ void IObserver.OnCompleted() => Parent.NotifyCompleted();
+ void IObserver.OnError(Exception error) => Parent.NotifyError(error);
+ void IObserver.OnNext(bool value) => Parent.NotifyActive(value);
}
}
}