diff --git a/src/Avalonia.Base/Data/TemplateBinding.cs b/src/Avalonia.Base/Data/TemplateBinding.cs index 09f04dfe70..0fd40cd09d 100644 --- a/src/Avalonia.Base/Data/TemplateBinding.cs +++ b/src/Avalonia.Base/Data/TemplateBinding.cs @@ -3,18 +3,21 @@ using System.Globalization; using Avalonia.Data.Converters; using Avalonia.Reactive; using Avalonia.Styling; +using Avalonia.Threading; namespace Avalonia.Data { /// /// A XAML binding to a property on a control's templated parent. /// - public class TemplateBinding : SingleSubscriberObservableBase, + public class TemplateBinding : IObservable, IBinding, IDescription, IAvaloniaSubject, - ISetterValue + ISetterValue, + IDisposable { + private IObserver? _observer; private bool _isSetterValue; private StyledElement? _target; private Type? _targetType; @@ -29,6 +32,28 @@ namespace Avalonia.Data Property = property; } + public IDisposable Subscribe(IObserver observer) + { + _ = observer ?? throw new ArgumentNullException(nameof(observer)); + Dispatcher.UIThread.VerifyAccess(); + + if (_observer != null) + { + throw new InvalidOperationException("The observable can only be subscribed once."); + } + + _observer = observer; + Subscribed(); + + return this; + } + + public virtual void Dispose() + { + Unsubscribed(); + _observer = null; + } + /// public InstancedBinding? Initiate( AvaloniaObject target, @@ -111,7 +136,7 @@ namespace Avalonia.Data /// void ISetterValue.Initialize(SetterBase setter) => _isSetterValue = true; - protected override void Subscribed() + private void Subscribed() { TemplatedParentChanged(); @@ -121,7 +146,7 @@ namespace Avalonia.Data } } - protected override void Unsubscribed() + private void Unsubscribed() { if (_target?.TemplatedParent is { } templatedParent) { @@ -147,12 +172,12 @@ namespace Avalonia.Data value = Converter.Convert(value, _targetType ?? typeof(object), ConverterParameter, CultureInfo.CurrentCulture); } - PublishNext(value); + _observer?.OnNext(value); _hasProducedValue = true; } else if (_hasProducedValue) { - PublishNext(AvaloniaProperty.UnsetValue); + _observer?.OnNext(AvaloniaProperty.UnsetValue); _hasProducedValue = false; } } diff --git a/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs b/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs index 53a0b43c63..10d42214c2 100644 --- a/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs +++ b/src/Avalonia.Base/Reactive/SingleSubscriberObservableBase.cs @@ -3,7 +3,7 @@ using Avalonia.Threading; namespace Avalonia.Reactive { - public abstract class SingleSubscriberObservableBase : IObservable, IDisposable + internal abstract class SingleSubscriberObservableBase : IObservable, IDisposable { private Exception? _error; private IObserver? _observer;