From 2c1efe3773b95a7c7ec59b97c4e75192a96b72dc Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 24 Aug 2017 22:57:04 +0200 Subject: [PATCH] Static resource as binding converter Enable using a `StaticResource` as a binding converter. Fixes #818. --- .../DynamicResourceExtension.cs | 7 +++-- .../StaticResourceExtension.cs | 27 +++++++++++-------- .../StaticResourceExtensionTests.cs | 27 +++++++++++++++++++ .../MarkupExtensions/TestValueConverter.cs | 20 ++++++++++++++ 4 files changed, 68 insertions(+), 13 deletions(-) create mode 100644 tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/TestValueConverter.cs diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs index 905bf16d1f..7937be60aa 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs @@ -3,7 +3,7 @@ using System; using System.ComponentModel; -using System.Reactive; +using System.Linq; using System.Reactive.Linq; using Avalonia.Controls; using Avalonia.Data; @@ -62,7 +62,10 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions var schemaContext = context.GetService()?.SchemaContext; var ambientProvider = context.GetService(); var xamlType = schemaContext.GetXamlType(typeof(T)); - return ambientProvider.GetFirstAmbientValue(xamlType) as T; + + // We override XamlType.CanAssignTo in BindingXamlType so the results we get back + // from GetAllAmbientValues aren't necessarily of the correct type. + return ambientProvider.GetAllAmbientValues(xamlType).OfType().FirstOrDefault(); } } } diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs index f92eca25bf..e3cd7b062b 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -32,7 +32,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions var schemaContext = context.GetService()?.SchemaContext; var ambientProvider = context.GetService(); var resourceProviderType = schemaContext.GetXamlType(typeof(IResourceProvider)); - var resourceProviders = ambientProvider.GetAllAmbientValues(resourceProviderType); + var ambientValues = ambientProvider.GetAllAmbientValues(resourceProviderType); // Look upwards though the ambient context for IResourceProviders which might be able // to give us the resource. @@ -43,18 +43,23 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions // // StaticResource_Can_Be_Assigned_To_Property_In_ControlTemplate_In_Styles_File // - foreach (IResourceProvider resourceProvider in resourceProviders) + foreach (var ambientValue in ambientValues) { - if (resourceProvider is IControl control && control.StylingParent != null) + // We override XamlType.CanAssignTo in BindingXamlType so the results we get back + // from GetAllAmbientValues aren't necessarily of the correct type. + if (ambientValue is IResourceProvider resourceProvider) { - // If we've got to a control that has a StylingParent then it's probably - // a top level control and its StylingParent is pointing to the global - // styles. If this is case just do a FindResource on it. - return control.FindResource(ResourceKey); - } - else if (resourceProvider.TryGetResource(ResourceKey, out var value)) - { - return value; + if (resourceProvider is IControl control && control.StylingParent != null) + { + // If we've got to a control that has a StylingParent then it's probably + // a top level control and its StylingParent is pointing to the global + // styles. If this is case just do a FindResource on it. + return control.FindResource(ResourceKey); + } + else if (resourceProvider.TryGetResource(ResourceKey, out var value)) + { + return value; + } } } diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs index 4f14f1eba8..ed3ab3cc52 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs @@ -332,6 +332,33 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions Assert.NotNull(listBox.ItemTemplate); } + [Fact] + public void StaticResource_Can_Be_Assigned_To_Converter() + { + using (StyledWindow()) + { + var xaml = @" + + + + + + +"; + + var loader = new AvaloniaXamlLoader(); + var window = (Window)loader.Load(xaml); + var textBlock = window.FindControl("textBlock"); + + window.DataContext = "foo"; + window.ApplyTemplate(); + + Assert.Equal("foobar", textBlock.Text); + } + } + [Fact] public void Control_Property_Is_Not_Updated_When_Parent_Is_Changed() { diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/TestValueConverter.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/TestValueConverter.cs new file mode 100644 index 0000000000..57570d8f5c --- /dev/null +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/TestValueConverter.cs @@ -0,0 +1,20 @@ +using System; +using System.Globalization; + +namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions +{ + public class TestValueConverter : IValueConverter + { + public string Append { get; set; } + + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return value.ToString() + Append; + } + + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + throw new NotImplementedException(); + } + } +}