using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml;
+using static Mono.Cecil.Cil.Instruction;
+using static Mono.Cecil.Cil.OpCodes;
+
namespace Xamarin.Forms.Build.Tasks
{
class SetPropertiesVisitor : IXamlNodeVisitor
var parentVar = Context.Variables[(IElementNode)parentNode];
string contentProperty;
- // Implicit Style Resource in a ResourceDictionary
- if (IsResourceDictionary((IElementNode)parentNode)
- && node.XmlType.Name == "Style"
- && !node.Properties.ContainsKey(XmlName.xKey)) {
- Context.IL.Emit(OpCodes.Ldloc, parentVar);
- Context.IL.Emit(OpCodes.Ldloc, Context.Variables[node]);
- Context.IL.Emit(OpCodes.Callvirt,
- Module.ImportReference(
- Module.ImportReference(typeof(ResourceDictionary))
- .Resolve()
- .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 1)));
- }
- // Resource without a x:Key in a ResourceDictionary
- else if (IsResourceDictionary((IElementNode)parentNode)
- && !node.Properties.ContainsKey(XmlName.xKey)) {
- throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", node);
- }
- // Resource in a ResourceDictionary
- else if (IsResourceDictionary((IElementNode)parentNode)
- && node.Properties.ContainsKey(XmlName.xKey)) {
-// IL_0013: ldloc.0
-// IL_0014: ldstr "key"
-// IL_0019: ldstr "foo"
-// IL_001e: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ResourceDictionary::Add(string, object)
- Context.IL.Emit(OpCodes.Ldloc, parentVar);
- Context.IL.Emit(OpCodes.Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
- var varDef = Context.Variables[node];
- Context.IL.Emit(OpCodes.Ldloc, varDef);
- if (varDef.VariableType.IsValueType)
- Context.IL.Emit(OpCodes.Box, Module.ImportReference(varDef.VariableType));
- Context.IL.Emit(OpCodes.Callvirt,
- Module.ImportReference(
- Module.ImportReference(typeof(ResourceDictionary))
- .Resolve()
- .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 2)));
+ if (CanAddToResourceDictionary(parentVar.VariableType, node, node, Context)) {
+ Context.IL.Emit(Ldloc, parentVar);
+ Context.IL.Append(AddToResourceDictionary(node, node, Context));
}
// Collection element, implicit content, or implicit collection element.
else if (parentVar.VariableType.ImplementsInterface(Module.ImportReference(typeof (IEnumerable))) && parentVar.VariableType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).Any()) {
TypeReference propertyType;
Context.IL.Append(GetPropertyValue(parent, parentList.XmlName, Context, node, out propertyType));
+ if (CanAddToResourceDictionary(propertyType, node, node, Context)) {
+ Context.IL.Append(AddToResourceDictionary(node, node, Context));
+ return;
+ }
var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, Module).First();
var adderRef = Module.ImportReference(adderTuple.Item1);
adderRef = Module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, Module));
{
}
- bool IsResourceDictionary(IElementNode node)
- {
- var parentVar = Context.Variables[(IElementNode)node];
- return parentVar.VariableType.FullName == "Xamarin.Forms.ResourceDictionary"
- || parentVar.VariableType.Resolve().BaseType?.FullName == "Xamarin.Forms.ResourceDictionary";
- }
-
public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
{
name = default(XmlName);
return true;
}
+ static bool CanAddToResourceDictionary(TypeReference collectionType, IElementNode node, IXmlLineInfo lineInfo, ILContext context)
+ {
+ if ( collectionType.FullName != "Xamarin.Forms.ResourceDictionary"
+ && collectionType.Resolve().BaseType?.FullName != "Xamarin.Forms.ResourceDictionary")
+ return false;
+
+ if (node.Properties.ContainsKey(XmlName.xKey))
+ return true;
+
+ if (node.XmlType.Name == "Style")
+ return true;
+
+ throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
+ }
+
static IEnumerable<Instruction> Add(VariableDefinition parent, XmlName propertyName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)
{
var module = context.Body.Method.Module;
foreach (var instruction in GetPropertyValue(parent, propertyName, context, iXmlLineInfo, out propertyType))
yield return instruction;
+ if (CanAddToResourceDictionary(propertyType, elementNode, iXmlLineInfo, context)) {
+ foreach (var instruction in AddToResourceDictionary(elementNode, iXmlLineInfo, context))
+ yield return instruction;
+ yield break;
+ }
+
var adderTuple = propertyType.GetMethods(md => md.Name == "Add" && md.Parameters.Count == 1, module).FirstOrDefault();
var adderRef = module.ImportReference(adderTuple.Item1);
adderRef = module.ImportReference(adderRef.ResolveGenericParameters(adderTuple.Item2, module));
yield return Instruction.Create(OpCodes.Pop);
}
+ static IEnumerable<Instruction> AddToResourceDictionary(IElementNode node, IXmlLineInfo lineInfo, ILContext context)
+ {
+ var module = context.Body.Method.Module;
+
+ if (node.Properties.ContainsKey(XmlName.xKey)) {
+// IL_0014: ldstr "key"
+// IL_0019: ldstr "foo"
+// IL_001e: callvirt instance void class [Xamarin.Forms.Core]Xamarin.Forms.ResourceDictionary::Add(string, object)
+ yield return Create(Ldstr, (node.Properties[XmlName.xKey] as ValueNode).Value as string);
+ var varDef = context.Variables[node];
+ yield return Create(Ldloc, varDef);
+ if (varDef.VariableType.IsValueType)
+ yield return Create(Box, module.ImportReference(varDef.VariableType));
+ yield return Create(Callvirt,
+ module.ImportReference(
+ module.ImportReference(typeof(ResourceDictionary))
+ .Resolve()
+ .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 2)));
+ yield break;
+ }
+ if (node.XmlType.Name == "Style") {
+ yield return Create(Ldloc, context.Variables[node]);
+ yield return Create(Callvirt,
+ module.ImportReference(
+ module.ImportReference(typeof(ResourceDictionary))
+ .Resolve()
+ .Methods.Single(md => md.Name == "Add" && md.Parameters.Count == 1)));
+ yield break;
+ }
+ }
+
public static TypeReference GetParameterType(ParameterDefinition param)
{
if (!param.ParameterType.IsGenericParameter)
#pragma warning disable 0414
static PropertyTestCase[] Properties = {
- new PropertyTestCase<View, ResourceDictionary> ("Resources", v => v.Resources, (v, o) => v.Resources = o, () => null, new ResourceDictionary ()),
new PropertyTestCase<View, bool> ("InputTransparent", v => v.InputTransparent, (v, o) => v.InputTransparent = o, () => false, true),
new PropertyTestCase<View, double> ("Scale", v => v.Scale, (v, o) => v.Scale = o, () => 1d, 2d),
new PropertyTestCase<View, double> ("Rotation", v => v.Rotation, (v, o) => v.Rotation = o, () => 0d, 90d),
Page _mainPage;
- ResourceDictionary _resources;
static SemaphoreSlim SaveSemaphore = new SemaphoreSlim(1, 1);
protected Application()
_appIndexProvider = provider;
}
+ ResourceDictionary _resources;
+ bool IResourcesProvider.IsResourcesCreated => _resources != null;
+
public ResourceDictionary Resources
{
- get { return _resources; }
+ get {
+ if (_resources != null)
+ return _resources;
+
+ _resources = new ResourceDictionary();
+ ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+ return _resources;
+ }
set
{
if (_resources == value)
internal override void OnParentResourcesChanged(IEnumerable<KeyValuePair<string, object>> values)
{
- if (Resources == null || Resources.Count == 0)
+ if (!((IResourcesProvider)this).IsResourcesCreated || Resources.Count == 0)
{
base.OnParentResourcesChanged(values);
return;
namespace Xamarin.Forms
{
- internal interface IResourcesProvider
+ interface IResourcesProvider
{
+ bool IsResourcesCreated { get; }
ResourceDictionary Resources { get; set; }
}
}
\ No newline at end of file
while (element != null)
{
var ve = element as IResourcesProvider;
- if (ve != null && ve.Resources != null)
+ if (ve != null && ve.IsResourcesCreated)
{
resources = resources ?? new Dictionary<string, object>();
foreach (KeyValuePair<string, object> res in ve.Resources.MergedResources)
while (element != null)
{
var ve = element as IResourcesProvider;
- if (ve != null && ve.Resources != null && ve.Resources.TryGetValue(key, out value))
+ if (ve != null && ve.IsResourcesCreated && ve.Resources.TryGetValue(key, out value))
return true;
var app = element as Application;
if (app != null && app.SystemResources != null && app.SystemResources.TryGetValue(key, out value))
}
//Fallback for the XF previewer
- if (Application.Current != null && Application.Current.Resources != null && Application.Current.Resources.TryGetValue(key, out value))
+ if (Application.Current != null && ((IResourcesProvider)Application.Current).IsResourcesCreated && Application.Current.Resources.TryGetValue(key, out value))
return true;
value = null;
double _mockY = -1;
- ResourceDictionary _resources;
LayoutConstraint _selfConstraint;
internal VisualElement()
BatchCommitted(this, new EventArg<VisualElement>(this));
}
+ ResourceDictionary _resources;
+ bool IResourcesProvider.IsResourcesCreated => _resources != null;
+
public ResourceDictionary Resources
{
- get { return _resources; }
+ get {
+ if (_resources != null)
+ return _resources;
+ _resources = new ResourceDictionary();
+ ((IResourceDictionary)_resources).ValuesChanged += OnResourcesChanged;
+ return _resources;
+ }
set
{
if (_resources == value)
if (values == null)
return;
- if (Resources == null || Resources.Count == 0)
+ if (!((IResourcesProvider)this).IsResourcesCreated || Resources.Count == 0)
{
base.OnParentResourcesChanged(values);
return;
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<ContentPage
+ xmlns="http://xamarin.com/schemas/2014/forms"
+ xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+ x:Class="Xamarin.Forms.Xaml.UnitTests.ImplicitResourceDictionaries">
+ <ContentPage.Resources>
+ <Color x:Key="notpink">Purple</Color>
+ <Color x:Key="pink">Pink</Color>
+ </ContentPage.Resources>
+ <Label x:Name="label" TextColor="{StaticResource notpink}"/>
+</ContentPage>
\ No newline at end of file
--- /dev/null
+using System;
+using NUnit.Framework;
+using Xamarin.Forms.Core.UnitTests;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+ public partial class ImplicitResourceDictionaries : ContentPage
+ {
+ public ImplicitResourceDictionaries()
+ {
+ InitializeComponent();
+ }
+
+ public ImplicitResourceDictionaries(bool useCompiledXaml)
+ {
+ //this stub will be replaced at compile time
+ }
+
+ [TestFixture]
+ public class Tests
+ {
+ [SetUp]
+ public void SetUp()
+ {
+ Device.PlatformServices = new MockPlatformServices();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void ImplicitRDonContentViews(bool useCompiledXaml)
+ {
+ var layout = new ImplicitResourceDictionaries(useCompiledXaml);
+ Assert.That(layout.label.TextColor, Is.EqualTo(Color.Purple));
+ }
+ }
+ }
+}
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8"?>
-<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Xamarin.Forms.Xaml.UnitTests.Bz49307">
- <Application.Resources>
- <!-- Application resource dictionary -->
- <Color x:Key="MyColor">#c2d1d3</Color>
- </Application.Resources>
-</Application>
+++ /dev/null
-using System;
-using System.Collections.Generic;
-using NUnit.Framework;
-using Xamarin.Forms;
-using Xamarin.Forms.Core.UnitTests;
-
-namespace Xamarin.Forms.Xaml.UnitTests
-{
- public partial class Bz49307 : Application
- {
- public Bz49307()
- {
- InitializeComponent();
- }
-
- public Bz49307(bool useCompiledXaml)
- {
- //this stub will be replaced at compile time
- }
-
- [TestFixture]
- class Tests
- {
- [SetUp]
- public void Setup()
- {
- Device.PlatformServices = new MockPlatformServices();
- }
-
- [TearDown]
- public void TearDown()
- {
- Device.PlatformServices = null;
- }
-
- [TestCase(true)]
- [TestCase(false)]
- public void ThrowOnMissingDictionary(bool useCompiledXaml)
- {
- if (useCompiledXaml)
- Assert.Throws<NullReferenceException>(() => new Bz49307(useCompiledXaml));
- else
- Assert.Throws(new XamlParseExceptionConstraint(5, 4), () => new Bz49307(useCompiledXaml));
- }
- }
- }
-}
\ No newline at end of file
using Xamarin.Forms;
using NUnit.Framework;
+using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
[TestFixture]
public class Tests
{
+ [SetUp]
+ public void SetUp()
+ {
+ Device.PlatformServices = new MockPlatformServices();
+ }
+
+ [TearDown]
+ public void TearDown()
+ {
+ Device.PlatformServices = null;
+ }
+
[TestCase (false)]
[TestCase (true)]
public void ResourcesDirectoriesCanBeXamlRoots (bool useCompiledXaml)
public void TestResourceNotFound ()
{
var view = new View ();
- var resource = view.Resources!= null ? view.Resources ["foo"] : null;
+ var resource = ((IResourcesProvider)view).IsResourcesCreated ? view.Resources ["foo"] : null;
Assert.Null (resource);
}
<Compile Include="I8.xaml.cs">
<DependentUpon>I8.xaml</DependentUpon>
</Compile>
- <Compile Include="Issues\Bz49307.xaml.cs">
- <DependentUpon>Bz49307.xaml</DependentUpon>
- </Compile>
<Compile Include="Issues\Unreported008.xaml.cs">
<DependentUpon>Unreported008.xaml</DependentUpon>
</Compile>
<Compile Include="Issues\Bz60575.xaml.cs">
<DependentUpon>Bz60575.xaml</DependentUpon>
</Compile>
- <Compile Include="ResourceLoader.xaml.cs" >
+ <Compile Include="ResourceLoader.xaml.cs">
<DependentUpon>ResourceLoader.xaml</DependentUpon>
</Compile>
<Compile Include="Issues\Bz60203.xaml.cs">
<Compile Include="Issues\Bz55862.xaml.cs">
<DependentUpon>Bz55862.xaml</DependentUpon>
</Compile>
+ <Compile Include="ImplicitResourceDictionaries.xaml.cs">
+ <DependentUpon>ImplicitResourceDictionaries.xaml</DependentUpon>
+ </Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
<EmbeddedResource Include="I8.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
- <EmbeddedResource Include="Issues\Bz49307.xaml">
- <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
- </EmbeddedResource>
<EmbeddedResource Include="Issues\Unreported008.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="Issues\Bz60575.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
- <EmbeddedResource Include="ResourceLoader.xaml" >
+ <EmbeddedResource Include="ResourceLoader.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="Issues\Bz60203.xaml">
<EmbeddedResource Include="Issues\Bz55862.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
+ <EmbeddedResource Include="ImplicitResourceDictionaries.xaml">
+ <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+ </EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
if (parentElement.SkipProperties.Contains(propertyName))
return;
- var source = Values [parentNode];
+ var source = Values[parentNode];
ProvideValue(ref value, node, source, propertyName);
SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
- } else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
var source = Values[parentNode];
ProvideValue(ref value, node, source, XmlName.Empty);
string contentProperty;
+ Exception xpe = null;
+ var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
+
+ //ResourceDictionary
+ if (xpe == null && TryAddToResourceDictionary(source as ResourceDictionary, value, xKey, node, out xpe))
+ return;
- // Implicit Style Resource in a ResourceDictionary
- if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && value is Style &&
- !node.Properties.ContainsKey(XmlName.xKey)) {
- ((ResourceDictionary)source).Add(value as Style);
- }
- // Resource without a x:Key in a ResourceDictionary
- else if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && !node.Properties.ContainsKey(XmlName.xKey))
- throw new XamlParseException("resources in ResourceDictionary require a x:Key attribute", node);
- // Resource in a ResourceDictionary
- else if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[parentElement]) && node.Properties.ContainsKey(XmlName.xKey))
- ((ResourceDictionary)source).Add((string)(((ValueNode)node.Properties[XmlName.xKey]).Value), value);
// Collection element, implicit content, or implicit collection element.
- else if (typeof(IEnumerable).IsAssignableFrom(Context.Types [parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) {
- if (!(typeof(ResourceDictionary).IsAssignableFrom(Context.Types [parentElement]))) {
- var addMethod =
- Context.Types [parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
- addMethod.Invoke(source, new [] { value });
- }
- } else if ((contentProperty = GetContentPropertyName(Context.Types [parentElement].GetTypeInfo())) != null) {
+ if (xpe == null && typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) {
+ var addMethod =
+ Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
+ addMethod.Invoke(source, new[] { value });
+ return;
+ }
+ if (xpe == null && (contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null) {
var name = new XmlName(node.NamespaceURI, contentProperty);
if (Skips.Contains(name))
return;
return;
SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
- } else
- throw new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
- } else if (IsCollectionItem(node, parentNode) && parentNode is ListNode) {
- var source = Values [parentNode.Parent];
+ return;
+ }
+ xpe = xpe ?? new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
+ if (Context.ExceptionHandler != null)
+ Context.ExceptionHandler(xpe);
+ else
+ throw xpe;
+ }
+ else if (IsCollectionItem(node, parentNode) && parentNode is ListNode) {
+ var source = Values[parentNode.Parent];
ProvideValue(ref value, node, source, XmlName.Empty);
-
var parentList = (ListNode)parentNode;
-
if (Skips.Contains(parentList.XmlName))
return;
+ Exception xpe = null;
+ var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
object _;
var collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _) as IEnumerable;
if (collection == null)
- throw new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
+ xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
- MethodInfo addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
- if (addMethod == null)
- throw new XamlParseException($"Value of {parentList.XmlName.LocalName} does not have a Add() method", node);
+ if (xpe == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, node, out xpe))
+ return;
- addMethod.Invoke(collection, new [] { Values [node] });
+ MethodInfo addMethod;
+ if (xpe == null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null) {
+ addMethod.Invoke(collection, new[] { Values[node] });
+ return;
+ }
+ xpe = xpe ?? new XamlParseException($"Value of {parentList.XmlName.LocalName} does not have a Add() method", node);
+ if (Context.ExceptionHandler != null)
+ Context.ExceptionHandler(xpe);
+ else
+ throw xpe;
}
}
-
-
public void Visit(RootNode node, INode parentNode)
{
}
var localName = propertyName.LocalName;
var serviceProvider = new XamlServiceProvider(node, context);
Exception xpe = null;
+ var xKey = node is IElementNode && ((IElementNode)node).Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)((IElementNode)node).Properties[XmlName.xKey]).Value as string : null;
+
//If it's an attached BP, update elementType and propertyName
var bpOwnerType = xamlelement.GetType();
return;
//If it's an already initialized property, add to it
- if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, lineInfo, serviceProvider, context, out xpe))
+ if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe))
return;
xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exists, or is not assignable, or mismatching type between value and property", lineInfo);
return false;
}
- static bool TryAddToProperty(object element, XmlName propertyName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
+ static bool TryAddToProperty(object element, XmlName propertyName, object value, string xKey, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
{
exception = null;
if (collection == null)
return false;
+ if (exception == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, lineInfo, out exception))
+ return true;
+
+ if (exception != null)
+ return false;
+
var addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
if (addMethod == null)
return false;
- ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty;
+ if (serviceProvider != null)
+ ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty;
+
addMethod.Invoke(collection, new [] { value.ConvertTo(addMethod.GetParameters() [0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
return true;
}
+ static bool TryAddToResourceDictionary(ResourceDictionary resourceDictionary, object value, string xKey, IXmlLineInfo lineInfo, out Exception exception)
+ {
+ exception = null;
+
+ if (resourceDictionary == null)
+ return false;
+
+ if (xKey != null)
+ resourceDictionary.Add(xKey, value);
+ else if (value is Style)
+ resourceDictionary.Add((Style)value);
+ else {
+ exception = new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
+ return false;
+ }
+ return true;
+ }
+
void SetTemplate(ElementTemplate dt, INode node)
{
#pragma warning disable 0612
object resource = null;
foreach (var p in valueProvider.ParentObjects) {
- var ve = p as VisualElement;
- var resDict = ve?.Resources ?? p as ResourceDictionary;
+ var irp = p as IResourcesProvider;
+ var resDict = irp != null && irp.IsResourcesCreated ? irp.Resources : p as ResourceDictionary;
if (resDict == null)
continue;
if (resDict.TryGetValue(Key, out resource))
internal object GetApplicationLevelResource(string key, IXmlLineInfo xmlLineInfo)
{
object resource;
- if (Application.Current == null || Application.Current.Resources == null || !Application.Current.Resources.TryGetValue(Key, out resource))
+ if (Application.Current == null || !((IResourcesProvider)Application.Current).IsResourcesCreated || !Application.Current.Resources.TryGetValue(Key, out resource))
throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
return resource;
}
<AttributeName>System.Diagnostics.DebuggerStepThrough</AttributeName>
</Attribute>
<Attribute>
- <AttributeName>System.Runtime.CompilerServices.AsyncStateMachine(typeof(Xamarin.Forms.Application/<SavePropertiesAsync>d__52))</AttributeName>
+ <AttributeName>System.Runtime.CompilerServices.AsyncStateMachine(typeof(Xamarin.Forms.Application/<SavePropertiesAsync>d__54))</AttributeName>
</Attribute>
</Attributes>
<ReturnValue>