From d065568be984d7f37be51287c453b1d0d4e6ab87 Mon Sep 17 00:00:00 2001 From: OronDF343 Date: Fri, 22 Mar 2019 12:05:11 +0200 Subject: [PATCH] Added MultiBinding.StringFormat + Relevant unit tests --- .../Avalonia.Markup/Data/MultiBinding.cs | 17 +++- .../Data/MultiBindingTests_Converters.cs | 81 +++++++++++++++++++ 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs diff --git a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs index 4e2fd40b21..f8c21deb8b 100644 --- a/src/Markup/Avalonia.Markup/Data/MultiBinding.cs +++ b/src/Markup/Avalonia.Markup/Data/MultiBinding.cs @@ -52,6 +52,11 @@ namespace Avalonia.Data /// public RelativeSource RelativeSource { get; set; } + /// + /// Gets or sets the string format. + /// + public string StringFormat { get; set; } + /// public InstancedBinding Initiate( IAvaloniaObject target, @@ -84,13 +89,23 @@ namespace Avalonia.Data private object ConvertValue(IList values, Type targetType) { - var converted = Converter.Convert(values, targetType, ConverterParameter, CultureInfo.CurrentCulture); + var culture = CultureInfo.CurrentCulture; + var converted = Converter.Convert(values, targetType, ConverterParameter, culture); if (converted == AvaloniaProperty.UnsetValue && FallbackValue != null) { converted = FallbackValue; } + // 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) && + (targetType == typeof(string) || targetType == typeof(object))) + { + converted = string.Format(culture, StringFormat, converted); + } + return converted; } } diff --git a/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs new file mode 100644 index 0000000000..bd4b5b9d04 --- /dev/null +++ b/tests/Avalonia.Markup.UnitTests/Data/MultiBindingTests_Converters.cs @@ -0,0 +1,81 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See license.md file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using Avalonia.Controls; +using Avalonia.Data; +using Avalonia.Data.Converters; +using Avalonia.Data.Core; +using Xunit; + +namespace Avalonia.Markup.UnitTests.Data +{ + public class MultiBindingTests_Converters + { + [Fact] + public void StringFormat_Should_Be_Applied() + { + var textBlock = new TextBlock + { + DataContext = new MultiBindingTests_Converters.Class1(), + }; + + var target = new MultiBinding + { + StringFormat = "Foo + Bar = {0}", + Converter = new SumOfDoublesConverter(), + Bindings = + { + new Binding(nameof(MultiBindingTests_Converters.Class1.Foo)), + new Binding(nameof(MultiBindingTests_Converters.Class1.Bar)), + } + }; + + textBlock.Bind(TextBlock.TextProperty, target); + + Assert.Equal("Foo + Bar = 3", textBlock.Text); + } + + [Fact] + public void StringFormat_Should_Not_Be_Applied_When_Binding_To_Non_String_Or_Object() + { + var textBlock = new TextBlock + { + DataContext = new MultiBindingTests_Converters.Class1(), + }; + + var target = new MultiBinding + { + StringFormat = "Hello {0}", + Converter = new SumOfDoublesConverter(), + Bindings = + { + new Binding(nameof(MultiBindingTests_Converters.Class1.Foo)), + new Binding(nameof(MultiBindingTests_Converters.Class1.Bar)), + } + }; + + textBlock.Bind(TextBlock.WidthProperty, target); + + Assert.Equal(3.0, textBlock.Width); + } + + private class SumOfDoublesConverter : IMultiValueConverter + { + public object Convert(IList values, Type targetType, object parameter, CultureInfo culture) + { + return values.OfType().Sum(); + } + } + + private class Class1 + { + public double Foo { get; set; } = 1; + public double Bar { get; set; } = 2; + } + } +}