|
|
@ -3,18 +3,21 @@ using System.Globalization; |
|
|
using Avalonia.Data.Converters; |
|
|
using Avalonia.Data.Converters; |
|
|
using Avalonia.Reactive; |
|
|
using Avalonia.Reactive; |
|
|
using Avalonia.Styling; |
|
|
using Avalonia.Styling; |
|
|
|
|
|
using Avalonia.Threading; |
|
|
|
|
|
|
|
|
namespace Avalonia.Data |
|
|
namespace Avalonia.Data |
|
|
{ |
|
|
{ |
|
|
/// <summary>
|
|
|
/// <summary>
|
|
|
/// A XAML binding to a property on a control's templated parent.
|
|
|
/// A XAML binding to a property on a control's templated parent.
|
|
|
/// </summary>
|
|
|
/// </summary>
|
|
|
public class TemplateBinding : SingleSubscriberObservableBase<object?>, |
|
|
public class TemplateBinding : IObservable<object?>, |
|
|
IBinding, |
|
|
IBinding, |
|
|
IDescription, |
|
|
IDescription, |
|
|
IAvaloniaSubject<object?>, |
|
|
IAvaloniaSubject<object?>, |
|
|
ISetterValue |
|
|
ISetterValue, |
|
|
|
|
|
IDisposable |
|
|
{ |
|
|
{ |
|
|
|
|
|
private IObserver<object?>? _observer; |
|
|
private bool _isSetterValue; |
|
|
private bool _isSetterValue; |
|
|
private StyledElement? _target; |
|
|
private StyledElement? _target; |
|
|
private Type? _targetType; |
|
|
private Type? _targetType; |
|
|
@ -29,6 +32,28 @@ namespace Avalonia.Data |
|
|
Property = property; |
|
|
Property = property; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public IDisposable Subscribe(IObserver<object?> 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; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
/// <inheritdoc/>
|
|
|
/// <inheritdoc/>
|
|
|
public InstancedBinding? Initiate( |
|
|
public InstancedBinding? Initiate( |
|
|
AvaloniaObject target, |
|
|
AvaloniaObject target, |
|
|
@ -111,7 +136,7 @@ namespace Avalonia.Data |
|
|
/// <inheritdoc/>
|
|
|
/// <inheritdoc/>
|
|
|
void ISetterValue.Initialize(SetterBase setter) => _isSetterValue = true; |
|
|
void ISetterValue.Initialize(SetterBase setter) => _isSetterValue = true; |
|
|
|
|
|
|
|
|
protected override void Subscribed() |
|
|
private void Subscribed() |
|
|
{ |
|
|
{ |
|
|
TemplatedParentChanged(); |
|
|
TemplatedParentChanged(); |
|
|
|
|
|
|
|
|
@ -121,7 +146,7 @@ namespace Avalonia.Data |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
protected override void Unsubscribed() |
|
|
private void Unsubscribed() |
|
|
{ |
|
|
{ |
|
|
if (_target?.TemplatedParent is { } templatedParent) |
|
|
if (_target?.TemplatedParent is { } templatedParent) |
|
|
{ |
|
|
{ |
|
|
@ -147,12 +172,12 @@ namespace Avalonia.Data |
|
|
value = Converter.Convert(value, _targetType ?? typeof(object), ConverterParameter, CultureInfo.CurrentCulture); |
|
|
value = Converter.Convert(value, _targetType ?? typeof(object), ConverterParameter, CultureInfo.CurrentCulture); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
PublishNext(value); |
|
|
_observer?.OnNext(value); |
|
|
_hasProducedValue = true; |
|
|
_hasProducedValue = true; |
|
|
} |
|
|
} |
|
|
else if (_hasProducedValue) |
|
|
else if (_hasProducedValue) |
|
|
{ |
|
|
{ |
|
|
PublishNext(AvaloniaProperty.UnsetValue); |
|
|
_observer?.OnNext(AvaloniaProperty.UnsetValue); |
|
|
_hasProducedValue = false; |
|
|
_hasProducedValue = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|