From 760f13f0934f3192b147645606e5a72894ee3caf Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 4 Nov 2020 14:54:18 +0100 Subject: [PATCH 1/6] fixed null reference exception when using MultiBinding without StringFormat and Converter --- src/Markup/Avalonia.Markup/Data/MultiBinding.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index 7aa1eed890..8b31f7b560 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -116,7 +116,8 @@ namespace Avalonia.Data } var culture = CultureInfo.CurrentCulture; - var converted = converter.Convert(values, targetType, ConverterParameter, culture); + var converted = converter?.Convert(values, targetType, ConverterParameter, culture) + ?? values.ToArray(); if (converted == null) { From 411b2278340dffa337715996ed9cc4f9a891ec96 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 4 Nov 2020 15:29:22 +0100 Subject: [PATCH 2/6] Adding test --- .../Data/MultiBindingTests.cs | 23 +++++++++++++++++++ .../Extensions/IEnummerableExtension.cs | 21 +++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs diff --git a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs index 64f5eb2a0e..b87922aa1e 100644 --- a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs +++ b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests.cs @@ -157,6 +157,29 @@ namespace Avalonia.Markup.UnitTests.Data Assert.Equal("1,2,Fallback", target.Text); } + [Fact] + public void MultiBinding_Without_StringFormat_And_Converter() + { + var source = new { A = 1, B = 2, C = 3 }; + var target = new ItemsControl { }; + + var binding = new MultiBinding + { + Bindings = new[] + { + new Binding { Path = "A", Source = source }, + new Binding { Path = "B", Source = source }, + new Binding { Path = "C", Source = source }, + }, + }; + + target.Bind(ItemsControl.ItemsProperty, binding); + Assert.Equal(target.ItemCount, 3); + Assert.Equal(target.Items.ElementAt(0), source.A); + Assert.Equal(target.Items.ElementAt(1), source.B); + Assert.Equal(target.Items.ElementAt(2), source.C); + } + private class ConcatConverter : IMultiValueConverter { public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) diff --git a/tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs b/tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs new file mode 100644 index 0000000000..33be06baed --- /dev/null +++ b/tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections; + +namespace Avalonia.Markup.UnitTests +{ + static class IEnummerableExtension + { + public static object ElementAt(this IEnumerable source, int index) + { + var i = -1; + var enumerator = source.GetEnumerator(); + + while (enumerator.MoveNext() && ++i < index); + if (i == index) + { + return enumerator.Current; + } + throw new ArgumentOutOfRangeException(nameof(index)); + } + } +} From 8ed53d47beb7194bfa8bb6a1df30f8b1bb2c0530 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 4 Nov 2020 16:14:29 +0100 Subject: [PATCH 3/6] fixes Should_Return_TargetNullValue_When_Value_Is_Null fails --- src/Markup/Avalonia.Markup/Data/MultiBinding.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index 8b31f7b560..5bdb424f68 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -48,7 +48,7 @@ namespace Avalonia.Data /// Gets or sets the binding priority. /// public BindingPriority Priority { get; set; } - + /// /// Gets or sets the relative source for the binding. /// @@ -77,12 +77,12 @@ namespace Avalonia.Data // We only respect `StringFormat` if the type of the property we're assigning to will // accept a string. Note that this is slightly different to WPF in that WPF only applies // `StringFormat` for target type `string` (not `object`). - if (!string.IsNullOrWhiteSpace(StringFormat) && + if (!string.IsNullOrWhiteSpace(StringFormat) && (targetType == typeof(string) || targetType == typeof(object))) { converter = new StringFormatMultiValueConverter(StringFormat, converter); } - + var children = Bindings.Select(x => x.Initiate(target, null)); var input = children.Select(x => x.Observable) @@ -116,8 +116,13 @@ namespace Avalonia.Data } var culture = CultureInfo.CurrentCulture; - var converted = converter?.Convert(values, targetType, ConverterParameter, culture) - ?? values.ToArray(); + object converted; + if (converter != null) + { + converted = converter.Convert(values, targetType, ConverterParameter, culture); + } + else + converted = values.ToArray(); if (converted == null) { From dbd0e3648e024719fe080d43a1c66e40b08eb320 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 5 Nov 2020 10:06:20 +0100 Subject: [PATCH 4/6] fix code smell --- src/Markup/Avalonia.Markup/Data/MultiBinding.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index 5bdb424f68..a48ac74f29 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -122,7 +122,9 @@ namespace Avalonia.Data converted = converter.Convert(values, targetType, ConverterParameter, culture); } else + { converted = values.ToArray(); + } if (converted == null) { From dd1941e6ec7d7bbf8af6fa429ebf5c72195765cf Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 5 Nov 2020 10:20:48 +0100 Subject: [PATCH 5/6] used ReadOnlyCollection instead of ToArray () --- src/Markup/Avalonia.Markup/Data/MultiBinding.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index a48ac74f29..cbc5f414f2 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -116,6 +116,7 @@ namespace Avalonia.Data } var culture = CultureInfo.CurrentCulture; + values = new System.Collections.ObjectModel.ReadOnlyCollection(values); object converted; if (converter != null) { @@ -123,7 +124,7 @@ namespace Avalonia.Data } else { - converted = values.ToArray(); + converted = values; } if (converted == null) From 47d6ba61dd7014087d6195e628420fa922d25694 Mon Sep 17 00:00:00 2001 From: workgroupengineering Date: Thu, 5 Nov 2020 19:45:52 +0100 Subject: [PATCH 6/6] Update tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes code smell Co-authored-by: Dariusz Komosiński --- .../Extensions/IEnummerableExtension.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs b/tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs index 33be06baed..0d9e2969e1 100644 --- a/tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs +++ b/tests/Avalonia.Markup.UnitTests/Extensions/IEnummerableExtension.cs @@ -3,7 +3,7 @@ using System.Collections; namespace Avalonia.Markup.UnitTests { - static class IEnummerableExtension + internal static class IEnumerableExtensions { public static object ElementAt(this IEnumerable source, int index) {