diff --git a/Xamarin.Forms.Core/TypeTypeConverter.cs b/Xamarin.Forms.Core/TypeTypeConverter.cs index 14e113f7287..e08b80d67b5 100644 --- a/Xamarin.Forms.Core/TypeTypeConverter.cs +++ b/Xamarin.Forms.Core/TypeTypeConverter.cs @@ -5,31 +5,24 @@ namespace Xamarin.Forms { - [Xaml.ProvideCompiled("Xamarin.Forms.Core.XamlC.TypeTypeConverter")] - [Xaml.TypeConversion(typeof(Type))] + [ProvideCompiled("Xamarin.Forms.Core.XamlC.TypeTypeConverter")] + [TypeConversion(typeof(Type))] public sealed class TypeTypeConverter : TypeConverter, IExtendedTypeConverter { - [Obsolete("IExtendedTypeConverter.ConvertFrom is obsolete as of version 2.2.0. Please use ConvertFromInvariantString (string, IServiceProvider) instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - object IExtendedTypeConverter.ConvertFrom(CultureInfo culture, object value, IServiceProvider serviceProvider) - { - return ((IExtendedTypeConverter)this).ConvertFromInvariantString((string)value, serviceProvider); - } - object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceProvider serviceProvider) { if (serviceProvider == null) - throw new ArgumentNullException("serviceProvider"); - var typeResolver = serviceProvider.GetService(typeof(IXamlTypeResolver)) as IXamlTypeResolver; - if (typeResolver == null) + throw new ArgumentNullException(nameof(serviceProvider)); + if (!(serviceProvider.GetService(typeof(IXamlTypeResolver)) is IXamlTypeResolver typeResolver)) throw new ArgumentException("No IXamlTypeResolver in IServiceProvider"); return typeResolver.Resolve(value, serviceProvider); } - public override object ConvertFromInvariantString(string value) - { - throw new NotImplementedException(); - } + public override object ConvertFromInvariantString(string value) => throw new NotImplementedException(); + + [Obsolete("IExtendedTypeConverter.ConvertFrom is obsolete as of version 2.2.0. Please use ConvertFromInvariantString (string, IServiceProvider) instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + object IExtendedTypeConverter.ConvertFrom(CultureInfo culture, object value, IServiceProvider serviceProvider) => ((IExtendedTypeConverter)this).ConvertFromInvariantString((string)value, serviceProvider); } } \ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/AppResources/Colors.xaml b/Xamarin.Forms.Xaml.UnitTests/AppResources/Colors.xaml index 93b60c303ca..6eb475d06b0 100644 --- a/Xamarin.Forms.Xaml.UnitTests/AppResources/Colors.xaml +++ b/Xamarin.Forms.Xaml.UnitTests/AppResources/Colors.xaml @@ -1,7 +1,8 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" + xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"> #FF4B14 #99253748 #253748 @@ -19,4 +20,8 @@ #C0C0C0 #4d4d4d #999999 + + \ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/AppResources/CompiledColors.xaml b/Xamarin.Forms.Xaml.UnitTests/AppResources/CompiledColors.xaml index d859c22e215..e75eed0e23c 100644 --- a/Xamarin.Forms.Xaml.UnitTests/AppResources/CompiledColors.xaml +++ b/Xamarin.Forms.Xaml.UnitTests/AppResources/CompiledColors.xaml @@ -2,7 +2,9 @@ + xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" + xmlns:local="using:Xamarin.Forms.Xaml.UnitTests"> + #FF4B14 #99253748 #253748 @@ -20,4 +22,8 @@ #C0C0C0 #4d4d4d #999999 + + \ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml new file mode 100644 index 00000000000..f5bd609a4c3 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml.cs new file mode 100644 index 00000000000..c8bf1bff705 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml.cs @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +using NUnit.Framework; +using Xamarin.Forms.Core.UnitTests; + +namespace Xamarin.Forms.Xaml.UnitTests +{ + public partial class Gh7531 : ContentPage + { + public Gh7531() => InitializeComponent(); + public Gh7531(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; + + [Test] + public void XamlOnlyResourceResolvesLocalAssembly([Values(false, true)]bool useCompiledXaml) + { + Gh7531 layout = null; + Assert.DoesNotThrow(() => layout = new Gh7531(useCompiledXaml)); + var style = ((ResourceDictionary)layout.Resources["Colors"])["style"] as Style; + Assert.That(style.TargetType, Is.EqualTo(typeof(Gh7531))); + } + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Xaml/HydrationContext.cs b/Xamarin.Forms.Xaml/HydrationContext.cs index 9599772c615..fdcaf97edcc 100644 --- a/Xamarin.Forms.Xaml/HydrationContext.cs +++ b/Xamarin.Forms.Xaml/HydrationContext.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Reflection; namespace Xamarin.Forms.Xaml { @@ -16,5 +17,6 @@ public HydrationContext() public HydrationContext ParentContext { get; set; } public Action ExceptionHandler { get; set; } public object RootElement { get; set; } + public Assembly RootAssembly { get; internal set; } } } \ No newline at end of file diff --git a/Xamarin.Forms.Xaml/ResourcesLoader.cs b/Xamarin.Forms.Xaml/ResourcesLoader.cs index 58d5f0f6e06..2da537c41d8 100644 --- a/Xamarin.Forms.Xaml/ResourcesLoader.cs +++ b/Xamarin.Forms.Xaml/ResourcesLoader.cs @@ -32,7 +32,7 @@ class ResourcesLoader : IResourcesLoader if (stream == null) throw new XamlParseException($"No resource found for '{resourceId}'.", lineInfo); using (var reader = new StreamReader(stream)) { - rd.LoadFromXaml(reader.ReadToEnd()); + rd.LoadFromXaml(reader.ReadToEnd(), assembly); return rd; } } diff --git a/Xamarin.Forms.Xaml/ViewExtensions.cs b/Xamarin.Forms.Xaml/ViewExtensions.cs index bea83890328..d388cdbdb2a 100644 --- a/Xamarin.Forms.Xaml/ViewExtensions.cs +++ b/Xamarin.Forms.Xaml/ViewExtensions.cs @@ -26,6 +26,7 @@ // THE SOFTWARE. using System; +using System.Reflection; namespace Xamarin.Forms.Xaml { @@ -42,5 +43,11 @@ public static TXaml LoadFromXaml(this TXaml view, string xaml) XamlLoader.Load(view, xaml); return view; } + + internal static TXaml LoadFromXaml(this TXaml view, string xaml, Assembly rootAssembly) + { + XamlLoader.Load(view, xaml, rootAssembly); + return view; + } } } \ No newline at end of file diff --git a/Xamarin.Forms.Xaml/XamlLoader.cs b/Xamarin.Forms.Xaml/XamlLoader.cs index f821fe9d951..5a4f11e8b1f 100644 --- a/Xamarin.Forms.Xaml/XamlLoader.cs +++ b/Xamarin.Forms.Xaml/XamlLoader.cs @@ -71,8 +71,10 @@ public static void Load(object view, Type callingType) } public static void Load(object view, string xaml) => Load(view, xaml, false); + public static void Load(object view, string xaml, bool useDesignProperties) => Load(view, xaml, null, useDesignProperties); + public static void Load(object view, string xaml, Assembly rootAssembly) => Load(view, xaml, rootAssembly, false); - public static void Load(object view, string xaml, bool useDesignProperties) + public static void Load(object view, string xaml, Assembly rootAssembly, bool useDesignProperties) { using (var textReader = new StringReader(xaml)) using (var reader = XmlReader.Create(textReader)) { @@ -95,7 +97,7 @@ public static void Load(object view, string xaml, bool useDesignProperties) void ehandler(Exception e) => ResourceLoader.ExceptionHandler2?.Invoke((e, XamlFilePathAttribute.GetFilePathForObject(view))); Visit(rootnode, new HydrationContext { RootElement = view, - + RootAssembly = rootAssembly ?? view.GetType().GetTypeInfo().Assembly, ExceptionHandler = doNotThrow ? ehandler : (Action)null }, useDesignProperties); break; diff --git a/Xamarin.Forms.Xaml/XamlServiceProvider.cs b/Xamarin.Forms.Xaml/XamlServiceProvider.cs index b6d2000b16b..849085722d0 100644 --- a/Xamarin.Forms.Xaml/XamlServiceProvider.cs +++ b/Xamarin.Forms.Xaml/XamlServiceProvider.cs @@ -17,11 +17,8 @@ internal XamlServiceProvider(INode node, HydrationContext context) IProvideValueTarget = new XamlValueTargetProvider(targetObject, node, context, null); if (context != null) IRootObjectProvider = new XamlRootObjectProvider(context.RootElement); - if (context != null && node != null) - { - IXamlTypeResolver = new XamlTypeResolver(node.NamespaceResolver, XamlParser.GetElementType, - context.RootElement.GetType().GetTypeInfo().Assembly); - + if (context != null && node != null) { + IXamlTypeResolver = new XamlTypeResolver(node.NamespaceResolver, XamlParser.GetElementType, context.RootAssembly); Add(typeof(IReferenceProvider), new ReferenceProvider(node)); } @@ -31,52 +28,49 @@ internal XamlServiceProvider(INode node, HydrationContext context) IValueConverterProvider = new ValueConverterProvider(); } - public XamlServiceProvider() - { - IValueConverterProvider = new ValueConverterProvider(); - } + public XamlServiceProvider() => IValueConverterProvider = new ValueConverterProvider(); internal IProvideValueTarget IProvideValueTarget { - get { return (IProvideValueTarget)GetService(typeof (IProvideValueTarget)); } - set { services[typeof (IProvideValueTarget)] = value; } + get => (IProvideValueTarget)GetService(typeof(IProvideValueTarget)); + set => services[typeof(IProvideValueTarget)] = value; } internal IXamlTypeResolver IXamlTypeResolver { - get { return (IXamlTypeResolver)GetService(typeof (IXamlTypeResolver)); } - set { services[typeof (IXamlTypeResolver)] = value; } + get => (IXamlTypeResolver)GetService(typeof(IXamlTypeResolver)); + set => services[typeof(IXamlTypeResolver)] = value; } internal IRootObjectProvider IRootObjectProvider { - get { return (IRootObjectProvider)GetService(typeof (IRootObjectProvider)); } - set { services[typeof (IRootObjectProvider)] = value; } + get => (IRootObjectProvider)GetService(typeof(IRootObjectProvider)); + set => services[typeof(IRootObjectProvider)] = value; } internal IXmlLineInfoProvider IXmlLineInfoProvider { - get { return (IXmlLineInfoProvider)GetService(typeof (IXmlLineInfoProvider)); } - set { services[typeof (IXmlLineInfoProvider)] = value; } - } - - [Obsolete] - [EditorBrowsable(EditorBrowsableState.Never)] - internal INameScopeProvider INameScopeProvider - { - get { return (INameScopeProvider)GetService(typeof (INameScopeProvider)); } - set { services[typeof (INameScopeProvider)] = value; } + get => (IXmlLineInfoProvider)GetService(typeof(IXmlLineInfoProvider)); + set => services[typeof(IXmlLineInfoProvider)] = value; } internal IValueConverterProvider IValueConverterProvider { - get { return (IValueConverterProvider)GetService(typeof (IValueConverterProvider)); } - set { services[typeof (IValueConverterProvider)] = value; } + get => (IValueConverterProvider)GetService(typeof(IValueConverterProvider)); + set => services[typeof(IValueConverterProvider)] = value; } public object GetService(Type serviceType) => services.TryGetValue(serviceType, out var service) ? service : null; public void Add(Type type, object service) => services.Add(type, service); + + [Obsolete] + [EditorBrowsable(EditorBrowsableState.Never)] + internal INameScopeProvider INameScopeProvider + { + get { return (INameScopeProvider)GetService(typeof(INameScopeProvider)); } + set { services[typeof(INameScopeProvider)] = value; } + } } class XamlValueTargetProvider : IProvideParentValues, IProvideValueTarget @@ -227,7 +221,7 @@ Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider, out Xam var namespaceuri = namespaceResolver.LookupNamespace(prefix); if (namespaceuri == null) { - exception = new XamlParseException(string.Format("No xmlns declaration for prefix \"{0}\"", prefix), xmlLineInfo); + exception = new XamlParseException($"No xmlns declaration for prefix \"{prefix}\"", xmlLineInfo); return null; } @@ -239,20 +233,14 @@ Type Resolve(string qualifiedTypeName, IServiceProvider serviceProvider, out Xam class XamlRootObjectProvider : IRootObjectProvider { - public XamlRootObjectProvider(object rootObject) - { - RootObject = rootObject; - } + public XamlRootObjectProvider(object rootObject) => RootObject = rootObject; public object RootObject { get; } } public class XmlLineInfoProvider : IXmlLineInfoProvider { - public XmlLineInfoProvider(IXmlLineInfo xmlLineInfo) - { - XmlLineInfo = xmlLineInfo; - } + public XmlLineInfoProvider(IXmlLineInfo xmlLineInfo) => XmlLineInfo = xmlLineInfo; public IXmlLineInfo XmlLineInfo { get; } }