summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs4
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs7
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledValueProviders/ICompiledValueProvider.cs13
-rw-r--r--Xamarin.Forms.Build.Tasks/CompiledValueProviders/SetterValueProvider.cs40
-rw-r--r--Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs24
-rw-r--r--Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj3
-rw-r--r--Xamarin.Forms.Core/Setter.cs1
7 files changed, 86 insertions, 6 deletions
diff --git a/Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs b/Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs
index 159bbf5f..5f1826db 100644
--- a/Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs
+++ b/Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs
@@ -26,7 +26,7 @@ namespace Xamarin.Forms.Build.Tasks
md.IsStatic &&
md.IsPublic &&
md.Parameters.Count == 1 &&
- md.Parameters [0].ParameterType.FullName == "Xamarin.Forms.BindableObject", module).SingleOrDefault()?.Item1;
+ md.Parameters[0].ParameterType.InheritsFromOrImplements(module.Import(typeof(BindableObject))), module).SingleOrDefault()?.Item1;
if (getter == null)
throw new XamlParseException($"Missing a public static Get{bpName} or a public instance property getter for the attached property \"{bpRef.DeclaringType}.{bpRef.Name}\"", iXmlLineInfo);
@@ -43,7 +43,7 @@ namespace Xamarin.Forms.Build.Tasks
md.IsStatic &&
md.IsPublic &&
md.Parameters.Count == 1 &&
- md.Parameters [0].ParameterType.FullName == "Xamarin.Forms.BindableObject", module).SingleOrDefault()?.Item1;
+ md.Parameters[0].ParameterType.InheritsFromOrImplements(module.Import(typeof(BindableObject))), module).SingleOrDefault()?.Item1;
var attributes = new List<CustomAttribute>();
if (property != null && property.HasCustomAttributes)
diff --git a/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs b/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs
index 92a53539..c1d11487 100644
--- a/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs
+++ b/Xamarin.Forms.Build.Tasks/CompiledConverters/BindablePropertyConverter.cs
@@ -18,7 +18,12 @@ namespace Xamarin.Forms.Core.XamlC
yield return Instruction.Create(OpCodes.Ldnull);
yield break;
}
+ var bpRef = GetBindablePropertyFieldReference(value, module, node);
+ yield return Instruction.Create(OpCodes.Ldsfld, bpRef);
+ }
+ public FieldReference GetBindablePropertyFieldReference(string value, ModuleDefinition module, BaseNode node)
+ {
FieldReference bpRef = null;
string typeName = null, propertyName = null;
@@ -49,7 +54,7 @@ namespace Xamarin.Forms.Core.XamlC
bpRef = GetBindablePropertyFieldReference(typeRef, propertyName, module);
if (bpRef == null)
throw new XamlParseException($"Can't resolve {propertyName} on {typeRef.Name}", node);
- yield return Instruction.Create(OpCodes.Ldsfld, bpRef);
+ return bpRef;
}
public static TypeReference GetTypeReference(string xmlType, ModuleDefinition module, BaseNode iNode)
diff --git a/Xamarin.Forms.Build.Tasks/CompiledValueProviders/ICompiledValueProvider.cs b/Xamarin.Forms.Build.Tasks/CompiledValueProviders/ICompiledValueProvider.cs
new file mode 100644
index 00000000..37418bd9
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledValueProviders/ICompiledValueProvider.cs
@@ -0,0 +1,13 @@
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+using Xamarin.Forms.Build.Tasks;
+
+namespace Xamarin.Forms.Xaml
+{
+ interface ICompiledValueProvider
+ {
+ IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context);
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Build.Tasks/CompiledValueProviders/SetterValueProvider.cs b/Xamarin.Forms.Build.Tasks/CompiledValueProviders/SetterValueProvider.cs
new file mode 100644
index 00000000..163bd9e7
--- /dev/null
+++ b/Xamarin.Forms.Build.Tasks/CompiledValueProviders/SetterValueProvider.cs
@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+using Xamarin.Forms.Xaml;
+using Xamarin.Forms.Build.Tasks;
+
+namespace Xamarin.Forms.Core.XamlC
+{
+ class SetterValueProvider : ICompiledValueProvider
+ {
+ public IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ModuleDefinition module, BaseNode node, ILContext context)
+ {
+ var valueNode = ((IElementNode)node).Properties[new XmlName("", "Value")];
+
+ //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.Import(module.Import(typeof(Setter)).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
diff --git a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
index 6a7a3bef..9cf62221 100644
--- a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
+++ b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
@@ -242,7 +242,8 @@ namespace Xamarin.Forms.Build.Tasks
}
public static IEnumerable<Instruction> ProvideValue(VariableDefinitionReference vardefref, ILContext context,
- ModuleDefinition module, ElementNode node, FieldReference bpRef = null, PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null)
+ ModuleDefinition module, ElementNode node, FieldReference bpRef = null,
+ PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null)
{
GenericInstanceType markupExtension;
IList<TypeReference> genericArguments;
@@ -306,8 +307,25 @@ namespace Xamarin.Forms.Build.Tasks
}
else if (context.Variables[node].VariableType.ImplementsInterface(module.Import(typeof (IValueProvider))))
{
- var markExt = module.Import(typeof (IValueProvider)).Resolve();
- var provideValueInfo = markExt.Methods.First(md => md.Name == "ProvideValue");
+ var valueProviderType = context.Variables[node].VariableType;
+ //If the IValueProvider has a ProvideCompiledAttribute that can be resolved, shortcut this
+ var compiledValueProviderName = valueProviderType?.GetCustomAttribute(module.Import(typeof(ProvideCompiledAttribute)))?.ConstructorArguments?[0].Value as string;
+ Type compiledValueProviderType;
+ if (compiledValueProviderName != null && (compiledValueProviderType = Type.GetType(compiledValueProviderName)) != null) {
+ var compiledValueProvider = Activator.CreateInstance(compiledValueProviderType);
+ var cProvideValue = typeof(ICompiledValueProvider).GetMethods().FirstOrDefault(md => md.Name == "ProvideValue");
+ var instructions = (IEnumerable<Instruction>)cProvideValue.Invoke(compiledValueProvider, new object[] {
+ vardefref,
+ context.Body.Method.Module,
+ node as BaseNode,
+ context});
+ foreach (var i in instructions)
+ yield return i;
+ yield break;
+ }
+
+ var valueProviderDef = module.Import(typeof (IValueProvider)).Resolve();
+ var provideValueInfo = valueProviderDef.Methods.First(md => md.Name == "ProvideValue");
var provideValue = module.Import(provideValueInfo);
vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object);
diff --git a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
index ef10720d..51dd60be 100644
--- a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
+++ b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj
@@ -105,6 +105,8 @@
<Compile Include="CompiledConverters\ThicknessTypeConverter.cs" />
<Compile Include="MethodBodyExtensions.cs" />
<Compile Include="CompiledConverters\TypeTypeConverter.cs" />
+ <Compile Include="CompiledValueProviders\SetterValueProvider.cs" />
+ <Compile Include="CompiledValueProviders\ICompiledValueProvider.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Target Name="AfterBuild">
@@ -128,6 +130,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="CompiledMarkupExtensions\" />
+ <Folder Include="CompiledValueProviders\" />
</ItemGroup>
<Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
diff --git a/Xamarin.Forms.Core/Setter.cs b/Xamarin.Forms.Core/Setter.cs
index b260e8f0..ea58d4fd 100644
--- a/Xamarin.Forms.Core/Setter.cs
+++ b/Xamarin.Forms.Core/Setter.cs
@@ -8,6 +8,7 @@ using Xamarin.Forms.Xaml;
namespace Xamarin.Forms
{
[ContentProperty("Value")]
+ [ProvideCompiled("Xamarin.Forms.Core.XamlC.SetterValueProvider")]
public sealed class Setter : IValueProvider
{
readonly ConditionalWeakTable<BindableObject, object> _originalValues = new ConditionalWeakTable<BindableObject, object>();