From 349ae5314df967236c2676f3439d69147a5b6e49 Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Fri, 23 Sep 2016 09:01:22 +0200 Subject: [XamlC] Implement IValueProvider.PropertyType (#345) --- .../BindablePropertyReferenceExtensions.cs | 61 ++++++++++ .../MethodReferenceExtensions.cs | 1 - Xamarin.Forms.Build.Tasks/NodeILExtensions.cs | 131 +++++---------------- .../PropertyDefinitionExtensions.cs | 24 +--- Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs | 87 +++++++------- .../Xamarin.Forms.Build.Tasks.csproj | 1 + Xamarin.Forms.Core/IProvideValueTarget.cs | 1 - .../MarkupExpressionParserTests.cs | 6 +- Xamarin.Forms.Xaml.UnitTests/OnPlatform.xaml | 18 ++- Xamarin.Forms.Xaml.UnitTests/OnPlatform.xaml.cs | 72 ++++++++++- .../MarkupExtensions/StaticResourceExtension.cs | 47 ++++---- Xamarin.Forms.Xaml/XamlServiceProvider.cs | 22 ++-- 12 files changed, 249 insertions(+), 222 deletions(-) create mode 100644 Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs diff --git a/Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs b/Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs new file mode 100644 index 00000000..159bbf5f --- /dev/null +++ b/Xamarin.Forms.Build.Tasks/BindablePropertyReferenceExtensions.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Xml; + +using Mono.Cecil; + +using Xamarin.Forms.Xaml; + +namespace Xamarin.Forms.Build.Tasks +{ + static class BindablePropertyReferenceExtensions + { + public static TypeReference GetBindablePropertyType(this FieldReference bpRef, IXmlLineInfo iXmlLineInfo, ModuleDefinition module) + { + if (!bpRef.Name.EndsWith("Property", StringComparison.InvariantCulture)) + throw new XamlParseException($"The name of the bindable property {bpRef.Name} does not ends with \"Property\". This is the kind of convention the world is build upon, a bit like Planck's constant.", iXmlLineInfo); + var bpName = bpRef.Name.Substring(0, bpRef.Name.Length - 8); + var owner = bpRef.DeclaringType; + TypeReference _; + + var getter = owner.GetProperty(pd => pd.Name == bpName, out _)?.GetMethod; + if (getter == null || getter.IsStatic || !getter.IsPublic) + getter = null; + getter = getter ?? owner.GetMethods(md => md.Name == $"Get{bpName}" && + md.IsStatic && + md.IsPublic && + md.Parameters.Count == 1 && + md.Parameters [0].ParameterType.FullName == "Xamarin.Forms.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); + return getter.ReturnType; + } + + public static TypeReference GetBindablePropertyTypeConverter(this FieldReference bpRef, ModuleDefinition module) + { + TypeReference _; + var owner = bpRef.DeclaringType; + var bpName = bpRef.Name.EndsWith("Property", StringComparison.Ordinal) ? bpRef.Name.Substring(0, bpRef.Name.Length - 8) : bpRef.Name; + var property = owner.GetProperty(pd => pd.Name == bpName, out _); + var staticGetter = owner.GetMethods(md => md.Name == $"Get{bpName}" && + md.IsStatic && + md.IsPublic && + md.Parameters.Count == 1 && + md.Parameters [0].ParameterType.FullName == "Xamarin.Forms.BindableObject", module).SingleOrDefault()?.Item1; + + var attributes = new List(); + if (property != null && property.HasCustomAttributes) + attributes.AddRange(property.CustomAttributes); + if (property != null && property.PropertyType.Resolve().HasCustomAttributes) + attributes.AddRange(property.PropertyType.Resolve().CustomAttributes); + if (staticGetter != null && staticGetter.HasCustomAttributes) + attributes.AddRange(staticGetter.CustomAttributes); + if (staticGetter != null && staticGetter.ReturnType.Resolve().HasCustomAttributes) + attributes.AddRange(staticGetter.ReturnType.Resolve().CustomAttributes); + + return attributes.FirstOrDefault(cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName))?.ConstructorArguments [0].Value as TypeReference; + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Build.Tasks/MethodReferenceExtensions.cs b/Xamarin.Forms.Build.Tasks/MethodReferenceExtensions.cs index 6240a201..3baa230c 100644 --- a/Xamarin.Forms.Build.Tasks/MethodReferenceExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/MethodReferenceExtensions.cs @@ -1,6 +1,5 @@ using System; using Mono.Cecil; -using Mono.Cecil.Rocks; namespace Xamarin.Forms.Build.Tasks { diff --git a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs index 3902c71b..084151ba 100644 --- a/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/NodeILExtensions.cs @@ -37,10 +37,8 @@ namespace Xamarin.Forms.Build.Tasks IEnumerable pushServiceProvider, bool boxValueTypes, bool unboxValueTypes) { var module = context.Body.Method.Module; - var targetTypeRef = GetBPReturnType(context, bpRef, node); - - TypeReference typeConverter; - bpRef.HasTypeConverter(module, out typeConverter); + var targetTypeRef = bpRef.GetBindablePropertyType(node, module); + var typeConverter = bpRef.GetBindablePropertyTypeConverter(module); return node.PushConvertedValue(context, targetTypeRef, typeConverter, pushServiceProvider, boxValueTypes, unboxValueTypes); @@ -186,101 +184,6 @@ namespace Xamarin.Forms.Build.Tasks throw new XamlParseException(string.Format("Enum value not found for {0}", value), lineInfo); } - static bool HasTypeConverter(this FieldReference bpRef, ModuleDefinition module, - out TypeReference typeConverterReference) - { - typeConverterReference = null; - - var declaringType = bpRef.DeclaringType; - var bpName = bpRef.Name; - var pName = bpName.EndsWith("Property", StringComparison.Ordinal) ? bpName.Substring(0, bpName.Length - 8) : bpName; - var property = declaringType.Resolve().Properties.FirstOrDefault(p => p.Name == pName); - CustomAttribute attr = null; - - if (property != null) - { - if (property.HasCustomAttributes) - { - attr = - property.CustomAttributes.FirstOrDefault( - cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName)); - } - if (attr == null && property.PropertyType.Resolve().HasCustomAttributes) - { - attr = - property.PropertyType.Resolve() - .CustomAttributes.FirstOrDefault( - cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName)); - } - - if (attr == null) - return false; - - typeConverterReference = attr.ConstructorArguments[0].Value as TypeReference; - return true; - } - - var getters = bpRef.DeclaringType.GetMethods(md => md.Name == "Get" + pName && - md.IsStatic && - md.Parameters.Count() == 1 && - md.Parameters[0].ParameterType.FullName == "Xamarin.Forms.BindableObject", module).SingleOrDefault(); - if (getters != null) - { - if (getters.Item1.HasCustomAttributes) - { - attr = - getters.Item1.CustomAttributes.FirstOrDefault( - cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName)); - } - else if (getters.Item1.ReturnType.Resolve().HasCustomAttributes) - { - attr = - getters.Item1.ReturnType.Resolve() - .CustomAttributes.FirstOrDefault( - cad => TypeConverterAttribute.TypeConvertersType.Contains(cad.AttributeType.FullName)); - } - - if (attr == null) - return false; - - typeConverterReference = attr.ConstructorArguments[0].Value as TypeReference; - return true; - } - - return false; - } - - static TypeReference GetBPReturnType(ILContext context, FieldReference bpRef, IXmlLineInfo lineInfo) - { - //Find a property with a matching name - var name = bpRef.Name; - if (!name.EndsWith("Property", StringComparison.Ordinal)) - return context.Body.Method.Module.TypeSystem.Object; - name = name.Substring(0, name.Length - 8); - - //First, check for a property - TypeReference declaringTypeRef; - var property = bpRef.DeclaringType.GetProperty(pd => pd.Name == name, out declaringTypeRef); - if (property != null) - return property.PropertyType; - - //Then check for getter or setter (attached BPs) - var getters = - bpRef.DeclaringType.GetMethods(md => md.Name == "Get" + name && - md.IsStatic && - md.Parameters.Count() == 1 && - md.Parameters [0].ParameterType.FullName == "Xamarin.Forms.BindableObject", context.Body.Method.Module) - .SingleOrDefault(); - if (getters != null) - return getters.Item1.ReturnType; - - //throws - throw new XamlParseException( - string.Format( - "Can not find a Property named \"{0}\" or a static method named \"Get{0}\" for BindableProperty \"{1}\"", name, - bpRef.Name), lineInfo); - } - public static IEnumerable PushXmlLineInfo(this INode node, ILContext context) { var module = context.Body.Method.Module; @@ -389,7 +292,30 @@ namespace Xamarin.Forms.Build.Tasks } } - public static IEnumerable PushServiceProvider(this INode node, ILContext context) + static IEnumerable PushTargetProperty(FieldReference bpRef, PropertyReference propertyRef, TypeReference declaringTypeReference, ModuleDefinition module) + { + if (bpRef != null) { + yield return Instruction.Create(OpCodes.Ldsfld, bpRef); + yield break; + } + if (propertyRef != null) { +// IL_0000: ldtoken [mscorlib]System.String +// IL_0005: call class [mscorlib]System.Type class [mscorlib] System.Type::GetTypeFromHandle(valuetype [mscorlib] System.RuntimeTypeHandle) +// IL_000a: ldstr "Foo" +// IL_000f: callvirt instance class [mscorlib] System.Reflection.PropertyInfo class [mscorlib] System.Type::GetProperty(string) + var getTypeFromHandle = module.Import(typeof(Type).GetMethod("GetTypeFromHandle", new [] { typeof(RuntimeTypeHandle) })); + var getPropertyInfo = module.Import(typeof(Type).GetMethod("GetProperty", new [] { typeof(string) })); + yield return Instruction.Create(OpCodes.Ldtoken, module.Import(declaringTypeReference ?? propertyRef.DeclaringType)); + yield return Instruction.Create(OpCodes.Call, module.Import(getTypeFromHandle)); + yield return Instruction.Create(OpCodes.Ldstr, propertyRef.Name); + yield return Instruction.Create(OpCodes.Callvirt, module.Import(getPropertyInfo)); + yield break; + } + yield return Instruction.Create(OpCodes.Ldnull); + yield break; + } + + public static IEnumerable PushServiceProvider(this INode node, ILContext context, FieldReference bpRef = null, PropertyReference propertyRef = null, TypeReference declaringTypeReference = null) { var module = context.Body.Method.Module; @@ -421,8 +347,11 @@ namespace Xamarin.Forms.Build.Tasks foreach (var instruction in pushParentIl) yield return instruction; + foreach (var instruction in PushTargetProperty(bpRef, propertyRef, declaringTypeReference, module)) + yield return instruction; + var targetProviderCtor = - module.Import(typeof (SimpleValueTargetProvider).GetConstructor(new[] { typeof (object[]) })); + module.Import(typeof (SimpleValueTargetProvider).GetConstructor(new[] { typeof (object[]), typeof(object) })); yield return Instruction.Create(OpCodes.Newobj, targetProviderCtor); yield return Instruction.Create(OpCodes.Callvirt, addService); } diff --git a/Xamarin.Forms.Build.Tasks/PropertyDefinitionExtensions.cs b/Xamarin.Forms.Build.Tasks/PropertyDefinitionExtensions.cs index 472a5658..7a56c9d1 100644 --- a/Xamarin.Forms.Build.Tasks/PropertyDefinitionExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/PropertyDefinitionExtensions.cs @@ -1,32 +1,14 @@ +using System; using Mono.Cecil; namespace Xamarin.Forms.Build.Tasks { static class PropertyDefinitionExtensions { - // public static PropertyDefinition MakeGeneric (this PropertyDefinition self, GenericInstanceType declaringTypeReference) - // { - // if (declaringTypeReference == null) - // throw new ArgumentNullException ("declaringTypeReference"); - // if (self == null) - // throw new ArgumentNullException ("self"); - // - // var propertyType = declaringTypeReference.GenericArguments[((GenericParameter)self.PropertyType).Position]; - // self.PropertyType = propertyType; - // self.SetMethod = self.SetMethod.MakeGeneric (propertyType).Resolve (); - // self.GetMethod.ReturnType = propertyType; - // - // return self; - // } - - public static TypeReference ResolveGenericPropertyType(this PropertyDefinition self, - TypeReference declaringTypeReference) + public static TypeReference ResolveGenericPropertyType(this PropertyDefinition self, TypeReference declaringTypeReference) { if (self.PropertyType.IsGenericParameter) - { - return - ((GenericInstanceType)declaringTypeReference).GenericArguments[((GenericParameter)self.PropertyType).Position]; - } + return ((GenericInstanceType)declaringTypeReference).GenericArguments [((GenericParameter)self.PropertyType).Position]; return self.PropertyType; } } diff --git a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs index 9bc09ce9..734a34c2 100644 --- a/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs +++ b/Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs @@ -81,10 +81,21 @@ namespace Xamarin.Forms.Build.Tasks parentNode = parentNode.Parent; } + if ((propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) && skips.Contains(propertyName)) + return; + //if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable var vardef = Context.Variables[node]; var vardefref = new VariableDefinitionReference(vardef); - Context.IL.Append(ProvideValue(vardefref, Context, Module, node)); + var localName = propertyName.LocalName; + TypeReference declaringTypeReference = null; + FieldReference bpRef = null; + PropertyDefinition propertyRef = null; + if (parentNode is IElementNode && propertyName != XmlName.Empty) { + bpRef = GetBindablePropertyReference(Context.Variables [(IElementNode)parentNode], propertyName.NamespaceURI, ref localName, Context, node); + propertyRef = Context.Variables [(IElementNode)parentNode].VariableType.GetProperty(pd => pd.Name == localName, out declaringTypeReference); + } + Context.IL.Append(ProvideValue(vardefref, Context, Module, node, bpRef:bpRef, propertyRef:propertyRef, propertyDeclaringTypeRef: declaringTypeReference)); if (vardef != vardefref.VariableDefinition) { vardef = vardefref.VariableDefinition; @@ -92,11 +103,8 @@ namespace Xamarin.Forms.Build.Tasks Context.Variables[node] = vardef; } - if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) + if (propertyName != XmlName.Empty) { - if (skips.Contains(propertyName)) - return; - if (propertyName == XmlName._CreateContent) SetDataTemplate((IElementNode)parentNode, node, Context, node); else @@ -221,7 +229,7 @@ namespace Xamarin.Forms.Build.Tasks } public static IEnumerable ProvideValue(VariableDefinitionReference vardefref, ILContext context, - ModuleDefinition module, ElementNode node) + ModuleDefinition module, ElementNode node, FieldReference bpRef = null, PropertyReference propertyRef = null, TypeReference propertyDeclaringTypeRef = null) { GenericInstanceType markupExtension; IList genericArguments; @@ -242,7 +250,7 @@ namespace Xamarin.Forms.Build.Tasks else vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First())); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); - foreach (var instruction in node.PushServiceProvider(context)) + foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); @@ -261,7 +269,7 @@ namespace Xamarin.Forms.Build.Tasks vardefref.VariableDefinition = new VariableDefinition(module.Import(genericArguments.First())); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); - foreach (var instruction in node.PushServiceProvider(context)) + foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition); @@ -274,7 +282,7 @@ namespace Xamarin.Forms.Build.Tasks vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); - foreach (var instruction in node.PushServiceProvider(context)) + foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition); @@ -287,7 +295,7 @@ namespace Xamarin.Forms.Build.Tasks vardefref.VariableDefinition = new VariableDefinition(module.TypeSystem.Object); yield return Instruction.Create(OpCodes.Ldloc, context.Variables[node]); - foreach (var instruction in node.PushServiceProvider(context)) + foreach (var instruction in node.PushServiceProvider(context, bpRef, propertyRef, propertyDeclaringTypeRef)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, provideValue); yield return Instruction.Create(OpCodes.Stloc, vardefref.VariableDefinition); @@ -297,20 +305,8 @@ namespace Xamarin.Forms.Build.Tasks public static IEnumerable SetPropertyValue(VariableDefinition parent, XmlName propertyName, INode valueNode, ILContext context, IXmlLineInfo iXmlLineInfo) { var module = context.Body.Method.Module; - var localName = propertyName.LocalName; - TypeReference declaringTypeReference; - - //If it's an attached BP, update elementType and propertyName - var bpOwnerType = parent.VariableType; - GetNameAndTypeRef(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, iXmlLineInfo); - FieldReference bpRef = bpOwnerType.GetField(fd => fd.Name == localName + "Property" && - fd.IsStatic && - fd.IsPublic, out declaringTypeReference); - if (bpRef != null) { - bpRef = module.Import(bpRef.ResolveGenericParameters(declaringTypeReference)); - bpRef.FieldType = module.Import(bpRef.FieldType); - } + var bpRef = GetBindablePropertyReference(parent, propertyName.NamespaceURI, ref localName, context, iXmlLineInfo); //If the target is an event, connect if (CanConnectEvent(parent, localName)) @@ -339,6 +335,25 @@ namespace Xamarin.Forms.Build.Tasks throw new XamlParseException($"No property, bindable property, or event found for '{localName}'", iXmlLineInfo); } + static FieldReference GetBindablePropertyReference(VariableDefinition parent, string namespaceURI, ref string localName, ILContext context, IXmlLineInfo iXmlLineInfo) + { + var module = context.Body.Method.Module; + TypeReference declaringTypeReference; + + //If it's an attached BP, update elementType and propertyName + var bpOwnerType = parent.VariableType; + GetNameAndTypeRef(ref bpOwnerType, namespaceURI, ref localName, context, iXmlLineInfo); + var name = $"{localName}Property"; + FieldReference bpRef = bpOwnerType.GetField(fd => fd.Name == name && + fd.IsStatic && + fd.IsPublic, out declaringTypeReference); + if (bpRef != null) { + bpRef = module.Import(bpRef.ResolveGenericParameters(declaringTypeReference)); + bpRef.FieldType = module.Import(bpRef.FieldType); + } + return bpRef; + } + static bool CanConnectEvent(VariableDefinition parent, string localName) { return parent.VariableType.GetEvent(ed => ed.Name == localName) != null; @@ -448,28 +463,10 @@ namespace Xamarin.Forms.Build.Tasks yield return Instruction.Create(OpCodes.Callvirt, module.Import(setBinding)); } - static TypeReference GetBindablePropertyType(FieldReference bpRef, IXmlLineInfo iXmlLineInfo, ILContext context) + static bool CanSetValue(FieldReference bpRef, INode node, IXmlLineInfo iXmlLineInfo, ILContext context) { var module = context.Body.Method.Module; - if (!bpRef.Name.EndsWith("Property", StringComparison.InvariantCulture)) - throw new XamlParseException($"The name of the bindable property {bpRef.Name} does not ends with \"Property\". This is the kind of convention the world is build upon, a bit like Planck's constant.", iXmlLineInfo); - var bpName = bpRef.Name.Substring(0, bpRef.Name.Length - 8); - var owner = bpRef.DeclaringType; - TypeReference _; - - var getter = owner.GetProperty(pd => pd.Name == bpName, out _)?.GetMethod; - if (getter == null || getter.IsStatic || !getter.IsPublic) - getter = null; - getter = getter ?? owner.GetMethods(md => md.Name == $"Get{bpName}" && md.IsStatic && md.IsPublic && md.Parameters.Count == 1, module).FirstOrDefault()?.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); - return getter.ReturnType; - } - - static bool CanSetValue(FieldReference bpRef, INode node, IXmlLineInfo iXmlLineInfo, ILContext context) - { if (bpRef == null) return false; @@ -484,7 +481,7 @@ namespace Xamarin.Forms.Build.Tasks if (!context.Variables.TryGetValue(elementNode, out varValue)) return false; - var bpTypeRef = GetBindablePropertyType(bpRef, iXmlLineInfo, context); + var bpTypeRef = bpRef.GetBindablePropertyType(iXmlLineInfo, module); return varValue.VariableType.InheritsFromOrImplements(bpTypeRef); } @@ -504,7 +501,7 @@ namespace Xamarin.Forms.Build.Tasks yield return Instruction.Create(OpCodes.Ldsfld, bpRef); if (valueNode != null) { - foreach (var instruction in valueNode.PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context), true, false)) + foreach (var instruction in valueNode.PushConvertedValue(context, bpRef, valueNode.PushServiceProvider(context, bpRef:bpRef), true, false)) yield return instruction; } else if (elementNode != null) { yield return Instruction.Create(OpCodes.Ldloc, context.Variables [elementNode]); @@ -572,7 +569,7 @@ namespace Xamarin.Forms.Build.Tasks yield return Instruction.Create(OpCodes.Ldloc, parent); if (valueNode != null) { - foreach (var instruction in valueNode.PushConvertedValue(context, propertyType, new ICustomAttributeProvider [] { property, propertyType.Resolve() }, valueNode.PushServiceProvider(context), false, true)) + foreach (var instruction in valueNode.PushConvertedValue(context, propertyType, new ICustomAttributeProvider [] { property, propertyType.Resolve() }, valueNode.PushServiceProvider(context, propertyRef:property), false, true)) yield return instruction; yield return Instruction.Create(OpCodes.Callvirt, propertySetterRef); } else if (elementNode != null) { diff --git a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj index 0b26e277..fd19f586 100644 --- a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj +++ b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj @@ -90,6 +90,7 @@ + diff --git a/Xamarin.Forms.Core/IProvideValueTarget.cs b/Xamarin.Forms.Core/IProvideValueTarget.cs index b8324b5e..13e4cb08 100644 --- a/Xamarin.Forms.Core/IProvideValueTarget.cs +++ b/Xamarin.Forms.Core/IProvideValueTarget.cs @@ -3,7 +3,6 @@ namespace Xamarin.Forms.Xaml public interface IProvideValueTarget { object TargetObject { get; } - object TargetProperty { get; } } } \ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/MarkupExpressionParserTests.cs b/Xamarin.Forms.Xaml.UnitTests/MarkupExpressionParserTests.cs index 7361235c..a026eda2 100644 --- a/Xamarin.Forms.Xaml.UnitTests/MarkupExpressionParserTests.cs +++ b/Xamarin.Forms.Xaml.UnitTests/MarkupExpressionParserTests.cs @@ -177,11 +177,7 @@ namespace Xamarin.Forms.Xaml.UnitTests } } - public object TargetProperty { - get { - throw new NotImplementedException (); - } - } + public object TargetProperty { get; } = null; } [Test] diff --git a/Xamarin.Forms.Xaml.UnitTests/OnPlatform.xaml b/Xamarin.Forms.Xaml.UnitTests/OnPlatform.xaml index bf44299b..7f470a4a 100644 --- a/Xamarin.Forms.Xaml.UnitTests/OnPlatform.xaml +++ b/Xamarin.Forms.Xaml.UnitTests/OnPlatform.xaml @@ -1,9 +1,23 @@ - + + + + + Bold + Italic + + + + + + + -