Skip to content

Commit

Permalink
[X] Pass the current assembly to parsing context (xamarin#7550)
Browse files Browse the repository at this point in the history
In case of Xaml-only RD, the rootAssembly is different from the assembly
of the rootType

- fixes xamarin#7531
  • Loading branch information
StephaneDelcroix authored and felipebaltazar committed Oct 16, 2019
1 parent 2760db0 commit 070fee9
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 57 deletions.
25 changes: 9 additions & 16 deletions Xamarin.Forms.Core/TypeTypeConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
7 changes: 6 additions & 1 deletion Xamarin.Forms.Xaml.UnitTests/AppResources/Colors.xaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<ResourceDictionary
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests">
<Color x:Key="AccentColor">#FF4B14</Color>
<Color x:Key="BlackOpacityColor">#99253748</Color>
<Color x:Key="BlackTextColor">#253748</Color>
Expand All @@ -19,4 +20,8 @@
<Color x:Key="DarkBackgroundColor">#C0C0C0</Color>
<Color x:Key="MediumGrayTextColor">#4d4d4d</Color>
<Color x:Key="LightTextColor">#999999</Color>

<Style TargetType="local:Gh7531" x:Key="style">
<Setter Property="BackgroundColor" Value="HotPink"/>
</Style>
</ResourceDictionary>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
<?xaml-comp compile="true" ?>
<ResourceDictionary
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml">
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:Xamarin.Forms.Xaml.UnitTests">

<Color x:Key="AccentColor">#FF4B14</Color>
<Color x:Key="BlackOpacityColor">#99253748</Color>
<Color x:Key="BlackTextColor">#253748</Color>
Expand All @@ -20,4 +22,8 @@
<Color x:Key="DarkBackgroundColor">#C0C0C0</Color>
<Color x:Key="MediumGrayTextColor">#4d4d4d</Color>
<Color x:Key="LightTextColor">#999999</Color>

<Style TargetType="local:Gh7531" x:Key="style">
<Setter Property="BackgroundColor" Value="HotPink"/>
</Style>
</ResourceDictionary>
7 changes: 7 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?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.Gh7531">
<ContentPage.Resources>
<ResourceDictionary Source="../AppResources/Colors.xaml" x:Key="Colors" />
<ResourceDictionary Source="../AppResources/CompiledColors.xaml" x:Key="CompiledColors" />
</ContentPage.Resources>
</ContentPage>
32 changes: 32 additions & 0 deletions Xamarin.Forms.Xaml.UnitTests/Issues/Gh7531.xaml.cs
Original file line number Diff line number Diff line change
@@ -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)));
}
}
}
}
2 changes: 2 additions & 0 deletions Xamarin.Forms.Xaml/HydrationContext.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Reflection;

namespace Xamarin.Forms.Xaml
{
Expand All @@ -16,5 +17,6 @@ public HydrationContext()
public HydrationContext ParentContext { get; set; }
public Action<Exception> ExceptionHandler { get; set; }
public object RootElement { get; set; }
public Assembly RootAssembly { get; internal set; }
}
}
2 changes: 1 addition & 1 deletion Xamarin.Forms.Xaml/ResourcesLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
7 changes: 7 additions & 0 deletions Xamarin.Forms.Xaml/ViewExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
// THE SOFTWARE.

using System;
using System.Reflection;

namespace Xamarin.Forms.Xaml
{
Expand All @@ -42,5 +43,11 @@ public static TXaml LoadFromXaml<TXaml>(this TXaml view, string xaml)
XamlLoader.Load(view, xaml);
return view;
}

internal static TXaml LoadFromXaml<TXaml>(this TXaml view, string xaml, Assembly rootAssembly)
{
XamlLoader.Load(view, xaml, rootAssembly);
return view;
}
}
}
6 changes: 4 additions & 2 deletions Xamarin.Forms.Xaml/XamlLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand All @@ -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<Exception>)null
}, useDesignProperties);
break;
Expand Down
60 changes: 24 additions & 36 deletions Xamarin.Forms.Xaml/XamlServiceProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}

Expand All @@ -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
Expand Down Expand Up @@ -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;
}

Expand All @@ -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; }
}
Expand Down

0 comments on commit 070fee9

Please sign in to comment.