Browse Source

Merge pull request #2385 from OronDF343/patch-1

Add support for ConverterParameter and StringFormat to MultiBinding
Steven Kirk 6 years ago
parent
commit
b3a497b8e7

+ 22 - 2
src/Markup/Avalonia.Markup/Data/MultiBinding.cs

@@ -23,10 +23,15 @@ namespace Avalonia.Data
         public IList<IBinding> Bindings { get; set; } = new List<IBinding>();
 
         /// <summary>
-        /// Gets or sets the <see cref="IValueConverter"/> to use.
+        /// Gets or sets the <see cref="IMultiValueConverter"/> to use.
         /// </summary>
         public IMultiValueConverter Converter { get; set; }
 
+        /// <summary>
+        /// Gets or sets a parameter to pass to <see cref="Converter"/>.
+        /// </summary>
+        public object ConverterParameter { get; set; }
+
         /// <summary>
         /// Gets or sets the value to use when the binding is unable to produce a value.
         /// </summary>
@@ -47,6 +52,11 @@ namespace Avalonia.Data
         /// </summary>
         public RelativeSource RelativeSource { get; set; }
 
+        /// <summary>
+        /// Gets or sets the string format.
+        /// </summary>
+        public string StringFormat { get; set; }
+
         /// <inheritdoc/>
         public InstancedBinding Initiate(
             IAvaloniaObject target,
@@ -79,13 +89,23 @@ namespace Avalonia.Data
 
         private object ConvertValue(IList<object> values, Type targetType)
         {
-            var converted = Converter.Convert(values, targetType, null, 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;
         }
     }

+ 81 - 0
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<object> values, Type targetType, object parameter, CultureInfo culture)
+            {
+                return values.OfType<double>().Sum();
+            }
+        }
+
+        private class Class1
+        {
+            public double Foo { get; set; } = 1;
+            public double Bar { get; set; } = 2;
+        }
+    }
+}