diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index 9ab5882361..7aa1eed890 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -107,6 +107,14 @@ namespace Avalonia.Data private object ConvertValue(IList values, Type targetType, IMultiValueConverter converter) { + for (var i = 0; i < values.Count; ++i) + { + if (values[i] is BindingNotification notification) + { + values[i] = notification.Value; + } + } + var culture = CultureInfo.CurrentCulture; var converted = converter.Convert(values, targetType, ConverterParameter, culture); diff --git a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs index 5773f5e6b0..64f5eb2a0e 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs @@ -113,6 +113,50 @@ namespace Avalonia.Markup.UnitTests.Data Assert.Equal("(null)", target.Text); } + [Fact] + public void Should_Pass_UnsetValue_To_Converter_For_Broken_Binding() + { + var source = new { A = 1, B = 2, C = 3 }; + var target = new TextBlock { DataContext = source }; + + var binding = new MultiBinding + { + Converter = new ConcatConverter(), + Bindings = new[] + { + new Binding { Path = "A" }, + new Binding { Path = "B" }, + new Binding { Path = "Missing" }, + }, + }; + + target.Bind(TextBlock.TextProperty, binding); + + Assert.Equal("1,2,(unset)", target.Text); + } + + [Fact] + public void Should_Pass_FallbackValue_To_Converter_For_Broken_Binding() + { + var source = new { A = 1, B = 2, C = 3 }; + var target = new TextBlock { DataContext = source }; + + var binding = new MultiBinding + { + Converter = new ConcatConverter(), + Bindings = new[] + { + new Binding { Path = "A" }, + new Binding { Path = "B" }, + new Binding { Path = "Missing", FallbackValue = "Fallback" }, + }, + }; + + target.Bind(TextBlock.TextProperty, binding); + + Assert.Equal("1,2,Fallback", target.Text); + } + private class ConcatConverter : IMultiValueConverter { public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs index 43c7525939..6730e3134d 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs @@ -1,6 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; using Avalonia.Controls; +using Avalonia.Controls.Presenters; using Avalonia.Data; +using Avalonia.Data.Converters; using Avalonia.UnitTests; +using Avalonia.VisualTree; using Xunit; namespace Avalonia.Markup.Xaml.UnitTests.Data @@ -54,5 +61,51 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data Assert.Equal("bar", textBlock.Text); } } + + [Fact] + public void MultiBinding_TemplatedParent_Works() + { + using (UnitTestApplication.Start(TestServices.StyledWindow)) + { + var xaml = @" + + + + + + + + + + + + + + + +"; + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var textBox = window.FindControl("textBox"); + + window.ApplyTemplate(); + textBox.ApplyTemplate(); + + var target = (TextPresenter)textBox.GetVisualChildren().Single(); + Assert.Equal("Foo,Bar", target.Text); + } + } + } + + public class ConcatConverter : IMultiValueConverter + { + public static ConcatConverter Instance { get; } = new ConcatConverter(); + + public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) + { + return string.Join(",", values); + } } }