From af99e177d7e3ecf514e7a8f4ad1406b6afd0ec1b Mon Sep 17 00:00:00 2001 From: Stephane Delcroix Date: Tue, 26 Feb 2019 20:09:16 +0100 Subject: [PATCH] [previewer] resilience on createvalue (#5369) - fixes #5171 --- .../DesignTimeLoaderTests.cs | 24 +++++++++++++++++++++- Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs | 18 ++++++++++------ Xamarin.Forms.Xaml/CreateValuesVisitor.cs | 11 ++++++---- .../FillResourceDictionariesVisitor.cs | 15 ++++++++------ 4 files changed, 51 insertions(+), 17 deletions(-) diff --git a/Xamarin.Forms.Xaml.UnitTests/DesignTimeLoaderTests.cs b/Xamarin.Forms.Xaml.UnitTests/DesignTimeLoaderTests.cs index b07d71b..4c60675 100644 --- a/Xamarin.Forms.Xaml.UnitTests/DesignTimeLoaderTests.cs +++ b/Xamarin.Forms.Xaml.UnitTests/DesignTimeLoaderTests.cs @@ -51,7 +51,7 @@ namespace Xamarin.Forms.Xaml.UnitTests } [Test] - public void ContentPageWithMissingType() + public void ContentPageWithMissingTypeMockviewReplacement() { XamlLoader.FallbackTypeResolver = (p, type) => type ?? typeof(MockView); @@ -69,6 +69,28 @@ namespace Xamarin.Forms.Xaml.UnitTests } [Test] + public void ContentPageWithMissingTypeNoReplacement() + { + XamlLoader.FallbackTypeResolver = (p, type) => type; + + var xaml = @" + + + + + + + + "; + + var page = (ContentPage)XamlLoader.Create(xaml, true); + Assert.That(page.Content, Is.Null); + } + + [Test] public void MissingTypeWithKnownProperty() { XamlLoader.FallbackTypeResolver = (p, type) => type ?? typeof(Button); diff --git a/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs b/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs index 8e35de0..448646e 100644 --- a/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs +++ b/Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs @@ -36,13 +36,15 @@ namespace Xamarin.Forms.Xaml public bool StopOnResourceDictionary { get; } public bool VisitNodeOnDataTemplate => true; public bool SkipChildren(INode node, INode parentNode) => false; - public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]); + public bool IsResourceDictionary(ElementNode node) => Context.Types.TryGetValue(node, out var type) && typeof(ResourceDictionary).IsAssignableFrom(type); public void Visit(ValueNode node, INode parentNode) { var parentElement = parentNode as IElementNode; var value = Values [node]; - var source = Values [parentNode]; + if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null) + return; + XmlName propertyName; if (TryGetPropertyName(node, parentNode, out propertyName)) { @@ -95,7 +97,8 @@ namespace Xamarin.Forms.Xaml parentElement = parentNode as IElementNode; } - var value = Values[node]; + if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null) + return; if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) { if (Skips.Contains(propertyName)) @@ -103,12 +106,14 @@ namespace Xamarin.Forms.Xaml if (parentElement.SkipProperties.Contains(propertyName)) return; - var source = Values[parentNode]; + if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null) + return; ProvideValue(ref value, node, source, propertyName); SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node); } else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) { - var source = Values[parentNode]; + if (!Values.TryGetValue(parentNode, out var source) && Context.ExceptionHandler != null) + return; ProvideValue(ref value, node, source, XmlName.Empty); string contentProperty; Exception xpe = null; @@ -143,7 +148,8 @@ namespace Xamarin.Forms.Xaml throw xpe; } else if (IsCollectionItem(node, parentNode) && parentNode is ListNode) { - var source = Values[parentNode.Parent]; + if (!Values.TryGetValue(parentNode.Parent, out var source) && Context.ExceptionHandler != null) + return; ProvideValue(ref value, node, source, XmlName.Empty); var parentList = (ListNode)parentNode; if (Skips.Contains(parentList.XmlName)) diff --git a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs index b9bb498..838a417 100644 --- a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs +++ b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs @@ -43,12 +43,15 @@ namespace Xamarin.Forms.Xaml { object value = null; - XamlParseException xpe; var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement?.GetType().GetTypeInfo().Assembly, - out xpe); - if (xpe != null) + out XamlParseException xpe); + if (xpe != null) { + if (Context.ExceptionHandler != null) { + Context.ExceptionHandler(xpe); + return; + } throw xpe; - + } Context.Types[node] = type; if (IsXaml2009LanguagePrimitive(node)) value = CreateLanguagePrimitive(type, node); diff --git a/Xamarin.Forms.Xaml/FillResourceDictionariesVisitor.cs b/Xamarin.Forms.Xaml/FillResourceDictionariesVisitor.cs index 5013ca6..a927ec9 100644 --- a/Xamarin.Forms.Xaml/FillResourceDictionariesVisitor.cs +++ b/Xamarin.Forms.Xaml/FillResourceDictionariesVisitor.cs @@ -25,7 +25,7 @@ namespace Xamarin.Forms.Xaml public void Visit(ValueNode node, INode parentNode) { - if (!typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)])) + if (!Context.Types.TryGetValue((IElementNode)parentNode, out var type) || !typeof(ResourceDictionary).IsAssignableFrom(type)) return; node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode); @@ -37,10 +37,11 @@ namespace Xamarin.Forms.Xaml public void Visit(ElementNode node, INode parentNode) { - var value = Values[node]; - XmlName propertyName; + if (!Values.TryGetValue(node, out var value) && Context.ExceptionHandler != null) + return; + //Set RD to VE - if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName)) { + if (typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]) && ApplyPropertiesVisitor.TryGetPropertyName(node, parentNode, out XmlName propertyName)) { if ((propertyName.LocalName == "Resources" || propertyName.LocalName.EndsWith(".Resources", StringComparison.Ordinal)) && value is ResourceDictionary) { var source = Values[parentNode]; @@ -51,7 +52,8 @@ namespace Xamarin.Forms.Xaml //Only proceed further if the node is a keyless RD if ( parentNode is IElementNode - && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)]) + && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType) + && typeof(ResourceDictionary).IsAssignableFrom(parentType) && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey)) node.Accept(new ApplyPropertiesVisitor(Context, stopOnResourceDictionary: false), parentNode); else if ( parentNode is ListNode @@ -74,7 +76,8 @@ namespace Xamarin.Forms.Xaml if (enode is null) return false; if ( parentNode is IElementNode - && typeof(ResourceDictionary).IsAssignableFrom(Context.Types[((IElementNode)parentNode)]) + && Context.Types.TryGetValue((IElementNode)parentNode, out var parentType) + && typeof(ResourceDictionary).IsAssignableFrom(parentType) && !((IElementNode)parentNode).Properties.ContainsKey(XmlName.xKey)) return true; if ( parentNode is ListNode -- 2.7.4