[Xaml] no longer require a ServiceProvider for Trigger and PropertyCo… (#771)
authorStephane Delcroix <stephane@delcroix.org>
Mon, 27 Feb 2017 08:33:23 +0000 (09:33 +0100)
committerGitHub <noreply@github.com>
Mon, 27 Feb 2017 08:33:23 +0000 (09:33 +0100)
* [Xaml] no longer require a ServiceProvider for Trigger and PropertyCondition

* fix

Xamarin.Forms.Build.Tasks/CompiledValueProviders/TriggerValueProvider.cs [deleted file]
Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
Xamarin.Forms.Core/Interactivity/PropertyCondition.cs
Xamarin.Forms.Core/Interactivity/Trigger.cs
docs/Xamarin.Forms.Core/Xamarin.Forms/PropertyCondition.xml
docs/Xamarin.Forms.Core/Xamarin.Forms/Trigger.xml

diff --git a/Xamarin.Forms.Build.Tasks/CompiledValueProviders/TriggerValueProvider.cs b/Xamarin.Forms.Build.Tasks/CompiledValueProviders/TriggerValueProvider.cs
deleted file mode 100644 (file)
index 6b4f0b6..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-using System.Collections.Generic;
-
-using Mono.Cecil;
-using Mono.Cecil.Cil;
-
-using Xamarin.Forms.Xaml;
-using Xamarin.Forms.Build.Tasks;
-using System.Xml;
-
-namespace Xamarin.Forms.Core.XamlC
-{
-       class TriggerValueProvider : ICompiledValueProvider
-       {
-               public IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context)
-               {
-                       INode valueNode = null;
-                       if (!((IElementNode)node).Properties.TryGetValue(new XmlName("", "Value"), out valueNode) &&
-                               !((IElementNode)node).Properties.TryGetValue(new XmlName("http://xamarin.com/schemas/2014/forms", "Value"), out valueNode) &&
-                               ((IElementNode)node).CollectionItems.Count == 1)
-                               valueNode = ((IElementNode)node).CollectionItems[0];
-
-                       if (valueNode == null)
-                               throw new XamlParseException("Missing Value for Trigger", (IXmlLineInfo)node);
-
-                       //if it's an elementNode, there's probably no need to convert it
-                       if (valueNode is IElementNode)
-                               yield break;
-
-                       var value = ((string)((ValueNode)valueNode).Value);
-                       var bpNode = ((ValueNode)((IElementNode)node).Properties[new XmlName("", "Property")]);
-                       var bpRef = (new BindablePropertyConverter()).GetBindablePropertyFieldReference((string)bpNode.Value, module, bpNode);
-
-                       TypeReference _;
-                       var setValueRef = module.ImportReference(module.ImportReference(typeof(Trigger)).GetProperty(p => p.Name == "Value", out _).SetMethod);
-
-                       //push the setter
-                       yield return Instruction.Create(OpCodes.Ldloc, vardefref.VariableDefinition);
-
-                       //push the value
-                       foreach (var instruction in ((ValueNode)valueNode).PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context, bpRef: bpRef), boxValueTypes: true, unboxValueTypes: false))
-                               yield return instruction;
-
-                       //set the value
-                       yield return Instruction.Create(OpCodes.Callvirt, setValueRef);
-               }
-       }
-}
\ No newline at end of file
index 880fa0c..1d9086f 100644 (file)
     <Compile Include="CompiledConverters\TypeTypeConverter.cs" />
     <Compile Include="CompiledValueProviders\SetterValueProvider.cs" />
     <Compile Include="CompiledValueProviders\ICompiledValueProvider.cs" />
-    <Compile Include="CompiledValueProviders\TriggerValueProvider.cs" />
     <Compile Include="CompiledValueProviders\PassthroughValueProvider.cs" />
     <Compile Include="CompiledConverters\ListStringTypeConverter.cs" />
     <Compile Include="CompiledMarkupExtensions\TypeExtension.cs" />
index 34f4e1b..b7f4013 100644 (file)
@@ -5,6 +5,8 @@ using Xamarin.Forms.Xaml;
 
 namespace Xamarin.Forms
 {
+       [ProvideCompiled("Xamarin.Forms.Core.XamlC.PassthroughValueProvider")]
+       [AcceptEmptyServiceProvider]
        public sealed class PropertyCondition : Condition, IValueProvider
        {
                readonly BindableProperty _stateProperty;
@@ -27,6 +29,13 @@ namespace Xamarin.Forms
                                if (IsSealed)
                                        throw new InvalidOperationException("Can not change Property once the Trigger has been applied.");
                                _property = value;
+
+                               //convert the value
+                               if (_property != null && s_valueConverter != null)
+                               {
+                                       Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
+                                       Value = s_valueConverter.Convert(Value, Property.ReturnType, minforetriever, null);
+                               }
                        }
                }
 
@@ -39,17 +48,20 @@ namespace Xamarin.Forms
                                        return;
                                if (IsSealed)
                                        throw new InvalidOperationException("Can not change Value once the Trigger has been applied.");
+
+                               //convert the value
+                               if (_property != null && s_valueConverter != null)
+                               {
+                                       Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
+                                       value = s_valueConverter.Convert(value, Property.ReturnType, minforetriever, null);
+                               }
                                _triggerValue = value;
                        }
                }
 
                object IValueProvider.ProvideValue(IServiceProvider serviceProvider)
                {
-                       var valueconverter = serviceProvider.GetService(typeof(IValueConverterProvider)) as IValueConverterProvider;
-                       Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
-
-                       object value = valueconverter.Convert(Value, Property.ReturnType, minforetriever, serviceProvider);
-                       Value = value;
+                       //This is no longer required
                        return this;
                }
 
@@ -58,10 +70,11 @@ namespace Xamarin.Forms
                        return (bool)bindable.GetValue(_stateProperty);
                }
 
+               static IValueConverterProvider s_valueConverter = DependencyService.Get<IValueConverterProvider>();
+
                internal override void SetUp(BindableObject bindable)
                {
                        object newvalue = bindable.GetValue(Property);
-
                        bool newState = (newvalue == Value) || (newvalue != null && newvalue.Equals(Value));
                        bindable.SetValue(_stateProperty, newState);
                        bindable.PropertyChanged += OnAttachedObjectPropertyChanged;
index a5d2c10..a18ef72 100644 (file)
@@ -1,12 +1,12 @@
 using System;
 using System.Collections.Generic;
-using System.Reflection;
 using Xamarin.Forms.Xaml;
 
 namespace Xamarin.Forms
 {
        [ContentProperty("Setters")]
-       [ProvideCompiled("Xamarin.Forms.Core.XamlC.TriggerValueProvider")]
+       [ProvideCompiled("Xamarin.Forms.Core.XamlC.PassthroughValueProvider")]
+       [AcceptEmptyServiceProvider]
        public sealed class Trigger : TriggerBase, IValueProvider
        {
                public Trigger([TypeConverter(typeof(TypeTypeConverter))] [Parameter("TargetType")] Type targetType) : base(new PropertyCondition(), targetType)
@@ -50,11 +50,7 @@ namespace Xamarin.Forms
 
                object IValueProvider.ProvideValue(IServiceProvider serviceProvider)
                {
-                       var valueconverter = serviceProvider.GetService(typeof(IValueConverterProvider)) as IValueConverterProvider;
-                       Func<MemberInfo> minforetriever = () => Property.DeclaringType.GetRuntimeProperty(Property.PropertyName);
-
-                       object value = valueconverter.Convert(Value, Property.ReturnType, minforetriever, serviceProvider);
-                       Value = value;
+                       //This is no longer required
                        return this;
                }
        }
index 7baedb0..13c1358 100644 (file)
       <InterfaceName>Xamarin.Forms.Xaml.IValueProvider</InterfaceName>
     </Interface>
   </Interfaces>
+  <Attributes>
+    <Attribute>
+      <AttributeName>Xamarin.Forms.Xaml.AcceptEmptyServiceProvider</AttributeName>
+    </Attribute>
+  </Attributes>
   <Docs>
     <summary>Class that represents a value comparison with a property.</summary>
     <remarks>
index ef04bf9..3bde4c7 100644 (file)
@@ -20,6 +20,9 @@
     <Attribute>
       <AttributeName>Xamarin.Forms.ContentProperty("Setters")</AttributeName>
     </Attribute>
+    <Attribute>
+      <AttributeName>Xamarin.Forms.Xaml.AcceptEmptyServiceProvider</AttributeName>
+    </Attribute>
   </Attributes>
   <Docs>
     <summary>Class that represents a property condition and an action that is performed when the condition is met.</summary>