diff --git a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs index 4b812e12f0..ec60695374 100644 --- a/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs +++ b/src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs @@ -20,6 +20,7 @@ namespace Avalonia.Markup.Xaml.Data /// public Binding() { + FallbackValue = AvaloniaProperty.UnsetValue; } /// @@ -27,6 +28,7 @@ namespace Avalonia.Markup.Xaml.Data /// /// The binding path. public Binding(string path) + : this() { Path = path; } @@ -122,12 +124,23 @@ namespace Avalonia.Markup.Xaml.Data throw new NotSupportedException(); } + var fallback = FallbackValue; + + // If we're binding to DataContext and our fallback is UnsetValue then override + // the fallback value to null, as broken bindings to DataContext must reset the + // DataContext in order to not propagate incorrect DataContexts to child controls. + // See Avalonia.Markup.Xaml.UnitTests.Data.DataContext_Binding_Should_Produce_Correct_Results. + if (targetProperty == Control.DataContextProperty && fallback == AvaloniaProperty.UnsetValue) + { + fallback = null; + } + var subject = new ExpressionSubject( observer, targetProperty?.PropertyType ?? typeof(object), + fallback, Converter ?? DefaultValueConverter.Instance, ConverterParameter, - FallbackValue, Priority); return new InstancedBinding(subject, Mode, Priority); diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs index a58a8614ee..70d3f7d161 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs @@ -36,7 +36,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions public IValueConverter Converter { get; set; } public object ConverterParameter { get; set; } public string ElementName { get; set; } - public object FallbackValue { get; set; } + public object FallbackValue { get; set; } = AvaloniaProperty.UnsetValue; public BindingMode Mode { get; set; } public string Path { get; set; } public BindingPriority Priority { get; set; } = BindingPriority.LocalValue; diff --git a/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs b/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs index 05bf818aad..0a3be26c18 100644 --- a/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs +++ b/src/Markup/Avalonia.Markup/Data/ExpressionSubject.cs @@ -41,16 +41,36 @@ namespace Avalonia.Markup.Data /// /// A parameter to pass to . /// + /// The binding priority. + public ExpressionSubject( + ExpressionObserver inner, + Type targetType, + IValueConverter converter, + object converterParameter = null, + BindingPriority priority = BindingPriority.LocalValue) + : this(inner, targetType, AvaloniaProperty.UnsetValue, converter, converterParameter, priority) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The type to convert the value to. /// /// The value to use when the binding is unable to produce a value. /// + /// The value converter to use. + /// + /// A parameter to pass to . + /// /// The binding priority. public ExpressionSubject( ExpressionObserver inner, - Type targetType, + Type targetType, + object fallbackValue, IValueConverter converter, object converterParameter = null, - object fallbackValue = null, BindingPriority priority = BindingPriority.LocalValue) { Contract.Requires(inner != null); @@ -117,7 +137,7 @@ namespace Avalonia.Markup.Data _inner.Expression, error.Exception.Message); - if (_fallbackValue != null) + if (_fallbackValue != AvaloniaProperty.UnsetValue) { if (TypeUtilities.TryConvert( type, @@ -162,7 +182,7 @@ namespace Avalonia.Markup.Data ConverterParameter, CultureInfo.CurrentUICulture); - if (_fallbackValue != null && + if (_fallbackValue != AvaloniaProperty.UnsetValue && (converted == AvaloniaProperty.UnsetValue || converted is BindingError)) { diff --git a/tests/Avalonia.Markup.UnitTests/Data/ExpressionSubjectTests.cs b/tests/Avalonia.Markup.UnitTests/Data/ExpressionSubjectTests.cs index 9ee32149e0..8b763e7fb9 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/ExpressionSubjectTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/ExpressionSubjectTests.cs @@ -123,8 +123,8 @@ namespace Avalonia.Markup.UnitTests.Data var target = new ExpressionSubject( new ExpressionObserver(data, "DoubleValue"), typeof(string), - DefaultValueConverter.Instance, - fallbackValue: "9.8"); + "9.8", + DefaultValueConverter.Instance); target.OnNext("foo"); @@ -162,7 +162,7 @@ namespace Avalonia.Markup.UnitTests.Data new ExpressionObserver(data, "DoubleValue"), typeof(string), converter.Object, - "foo"); + converterParameter: "foo"); target.Subscribe(_ => { }); @@ -178,7 +178,7 @@ namespace Avalonia.Markup.UnitTests.Data new ExpressionObserver(data, "DoubleValue"), typeof(string), converter.Object, - "foo"); + converterParameter: "foo"); target.OnNext("bar");