[Xaml] Allow OnPlat markup in Styles (#3995)
authorStephane Delcroix <stephane@delcroix.org>
Tue, 16 Oct 2018 07:25:17 +0000 (09:25 +0200)
committerGitHub <noreply@github.com>
Tue, 16 Oct 2018 07:25:17 +0000 (09:25 +0200)
- fixes #3862

Xamarin.Forms.Xaml.UnitTests/Issues/Gh3862.xaml [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/Issues/Gh3862.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/MarkupExpressionParserTests.cs
Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj
Xamarin.Forms.Xaml/MarkupExtensions/OnIdiomExtension.cs
Xamarin.Forms.Xaml/MarkupExtensions/OnPlatformExtension.cs

diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3862.xaml b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3862.xaml
new file mode 100644 (file)
index 0000000..0c490b3
--- /dev/null
@@ -0,0 +1,10 @@
+<?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.Gh3862">
+    <ContentPage.Resources>
+        <Style TargetType="Label" x:Key="style">
+            <Setter Property="TextColor" Value="Pink" />
+            <Setter Property="IsVisible" Value="{OnPlatform Android=True, iOS=False}" />
+        </Style>
+    </ContentPage.Resources>
+    <Label Style="{StaticResource style}" x:Name="label"/>
+</ContentPage>
diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3862.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/Issues/Gh3862.xaml.cs
new file mode 100644 (file)
index 0000000..5925892
--- /dev/null
@@ -0,0 +1,52 @@
+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 Gh3862 : ContentPage
+       {
+               public Gh3862()
+               {
+                       InitializeComponent();
+               }
+
+               public Gh3862(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(false), TestCase(true)]
+                       public void OnPlatformMarkupInStyle(bool useCompiledXaml)
+                       {
+                               Device.PlatformServices = new MockPlatformServices { RuntimePlatform = Device.iOS };
+                               var layout = new Gh3862(useCompiledXaml);
+                               Assert.That(layout.label.TextColor, Is.EqualTo(Color.Pink));
+                               Assert.That(layout.label.IsVisible, Is.False);
+
+                               Device.PlatformServices = new MockPlatformServices { RuntimePlatform = Device.Android };
+
+                               layout = new Gh3862(useCompiledXaml);
+                               Assert.That(layout.label.IsVisible, Is.True);
+
+                       }
+               }
+       }
+}
index 9f34b46..37ba170 100644 (file)
@@ -170,11 +170,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                                }
                        }
 
-                       public object TargetObject {
-                               get {
-                                       throw new NotImplementedException ();
-                               }
-                       }
+                       public object TargetObject => null;
 
                        public object TargetProperty { get; set; } = null;
                }
index 8324a7a..0c0ec1b 100644 (file)
     <Compile Include="Issues\Gh3606.xaml.cs">
       <DependentUpon>Gh3606.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Issues\Gh3862.xaml.cs">
+      <DependentUpon>Gh3862.xaml</DependentUpon>
+    </Compile>
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <PropertyGroup>
       <SubType>Designer</SubType>
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
+    <EmbeddedResource Include="Issues\Gh3862.xaml">
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
   </ItemGroup>
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
index 531c1c0..5383803 100644 (file)
@@ -22,20 +22,32 @@ namespace Xamarin.Forms.Xaml
 
                public object ProvideValue(IServiceProvider serviceProvider)
                {
-                       var lineInfo = serviceProvider?.GetService<IXmlLineInfoProvider>()?.XmlLineInfo;
-                       if (Default == null && Phone == null &&
-                               Tablet == null && Desktop == null && TV == null && Watch == null)
-                       {
+                       if (   Default == null
+                           && Phone == null
+                           && Tablet == null
+                           && Desktop == null
+                           && TV == null
+                           && Watch == null) {
+                               var lineInfo = serviceProvider?.GetService<IXmlLineInfoProvider>()?.XmlLineInfo;
                                throw new XamlParseException("OnIdiomExtension requires a non-null value to be specified for at least one idiom or Default.", lineInfo ?? new XmlLineInfo());
                        }
 
                        var valueProvider = serviceProvider?.GetService<IProvideValueTarget>() ?? throw new ArgumentException();
 
-                       var bp = valueProvider.TargetProperty as BindableProperty;
-                       var pi = valueProvider.TargetProperty as PropertyInfo;
-                       var propertyType = bp?.ReturnType
-                               ?? pi?.PropertyType
-                               ?? throw new InvalidOperationException("Cannot determine property to provide the value for.");
+                       BindableProperty bp;
+                       PropertyInfo pi = null;
+                       Type propertyType = null;
+
+                       if (valueProvider.TargetObject is Setter setter) {
+                               bp = setter.Property;
+                       }
+                       else {
+                               bp = valueProvider.TargetProperty as BindableProperty;
+                               pi = valueProvider.TargetProperty as PropertyInfo;
+                       }
+                       propertyType = bp?.ReturnType
+                                                         ?? pi?.PropertyType
+                                                         ?? throw new InvalidOperationException("Cannot determine property to provide the value for.");
 
                        var value = GetValue();
                        var info = propertyType.GetTypeInfo();
index b22cb68..daeae80 100644 (file)
@@ -22,21 +22,34 @@ namespace Xamarin.Forms.Xaml
 
                public object ProvideValue(IServiceProvider serviceProvider)
                {
-                       var lineInfo = serviceProvider?.GetService<IXmlLineInfoProvider>()?.XmlLineInfo;
-                       if (Android == null && GTK == null && iOS == null && 
-                               macOS == null && Tizen == null && UWP == null && 
-                               WPF == null && Default == null)
-                       {
-                               throw new XamlParseException("OnPlatformExtension requires a non-null value to be specified for at least one platform or Default.", lineInfo ?? new XmlLineInfo());
+                       if (   Android == null
+                           && GTK == null
+                           && iOS == null
+                           && macOS == null
+                           && Tizen == null
+                           && UWP == null
+                           && WPF == null
+                           && Default == null) {
+                               var lineInfo = serviceProvider?.GetService<IXmlLineInfoProvider>()?.XmlLineInfo ?? new XmlLineInfo();
+                               throw new XamlParseException("OnPlatformExtension requires a non-null value to be specified for at least one platform or Default.", lineInfo);
                        }
 
                        var valueProvider = serviceProvider?.GetService<IProvideValueTarget>() ?? throw new ArgumentException();
 
-                       var bp = valueProvider.TargetProperty as BindableProperty;
-                       var pi = valueProvider.TargetProperty as PropertyInfo;
-                       var propertyType = bp?.ReturnType 
-                               ?? pi?.PropertyType 
-                               ?? throw new InvalidOperationException("Cannot determine property to provide the value for.");
+                       BindableProperty bp;
+                       PropertyInfo pi = null;
+                       Type propertyType = null;
+
+                       if (valueProvider.TargetObject is Setter setter) {
+                               bp = setter.Property;
+                       }
+                       else {
+                               bp = valueProvider.TargetProperty as BindableProperty;
+                               pi = valueProvider.TargetProperty as PropertyInfo;
+                       }
+                       propertyType = bp?.ReturnType
+                                                         ?? pi?.PropertyType
+                                                         ?? throw new InvalidOperationException("Cannot determine property to provide the value for.");
 
                        var value = GetValue();
                        var info = propertyType.GetTypeInfo();