// Copyright (c) The Perspex 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.Globalization; using System.Reactive.Linq; using System.Reactive.Subjects; using Perspex.Data; using Perspex.Utilities; namespace Perspex.Markup.Data { /// /// Turns an into a subject that can be bound two-way with /// a value converter. /// public class ExpressionSubject : ISubject, IDescription { private readonly ExpressionObserver _inner; private readonly Type _targetType; private readonly object _fallbackValue; private readonly BindingPriority _priority; /// /// Initializes a new instance of the class. /// /// The . /// The type to convert the value to. public ExpressionSubject(ExpressionObserver inner, Type targetType) : this(inner, targetType, DefaultValueConverter.Instance) { } /// /// Initializes a new instance of the class. /// /// The . /// The type to convert the value to. /// The value converter to use. /// /// A parameter to pass to . /// /// /// The value to use when the binding is unable to produce a value. /// /// The binding priority. public ExpressionSubject( ExpressionObserver inner, Type targetType, IValueConverter converter, object converterParameter = null, object fallbackValue = null, BindingPriority priority = BindingPriority.LocalValue) { Contract.Requires(inner != null); Contract.Requires(targetType != null); Contract.Requires(converter != null); _inner = inner; _targetType = targetType; Converter = converter; ConverterParameter = converterParameter; _fallbackValue = fallbackValue; _priority = priority; } /// /// Gets the converter to use on the expression. /// public IValueConverter Converter { get; } /// /// Gets a parameter to pass to . /// public object ConverterParameter { get; } /// string IDescription.Description => _inner.Expression; /// public void OnCompleted() { } /// public void OnError(Exception error) { } /// public void OnNext(object value) { var type = _inner.ResultType; if (type != null) { var converted = Converter.ConvertBack( value, type, ConverterParameter, CultureInfo.CurrentUICulture); if (converted == PerspexProperty.UnsetValue) { converted = TypeUtilities.Default(type); } _inner.SetValue(converted, _priority); } } /// public IDisposable Subscribe(IObserver observer) { return _inner.Select(ConvertValue).Subscribe(observer); } private object ConvertValue(object value) { var converted = Converter.Convert( value, _targetType, ConverterParameter, CultureInfo.CurrentUICulture); if (converted == PerspexProperty.UnsetValue && _fallbackValue != null) { converted = _fallbackValue; } return converted; } } }