Force conversion to target type when Static Resource returns OnPlatform<T>
authorE.Z. Hart <hartez@users.noreply.github.com>
Thu, 7 Apr 2016 06:12:07 +0000 (00:12 -0600)
committerJason Smith <jason.smith@xamarin.com>
Thu, 7 Apr 2016 06:12:07 +0000 (23:12 -0700)
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla39636.xaml [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla39636.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Core.Android.UITests/Xamarin.Forms.Core.Android.UITests.csproj
Xamarin.Forms.Xaml/MarkupExtensions/StaticResourceExtension.cs

diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla39636.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla39636.xaml
new file mode 100644 (file)
index 0000000..1f90ee8
--- /dev/null
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<local:TestContentPage xmlns="http://xamarin.com/schemas/2014/forms"
+             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+                  xmlns:local="clr-namespace:Xamarin.Forms.Controls"
+             x:Class="Xamarin.Forms.Controls.Issues.Bugzilla39636">
+
+  <local:TestContentPage.Resources>
+    <ResourceDictionary>
+
+      <OnPlatform
+          x:Key="SizeMedium"
+          x:TypeArguments="x:Double"
+          iOS="40"
+          Android="30"
+          WinPhone="60" />
+
+      <x:Double x:Key="SizeLarge">80</x:Double>
+
+    </ResourceDictionary>
+  </local:TestContentPage.Resources>
+
+  <local:TestContentPage.Content>
+    <StackLayout HorizontalOptions="Fill" VerticalOptions="Fill">
+      <Label Text="Success"></Label>
+      <Label Text="If there is a blue box and a red box below, this test has passed. If the application crashes, the test has not passed."></Label>
+      <BoxView HorizontalOptions="Center" VerticalOptions="Center" BackgroundColor="Blue" WidthRequest="{StaticResource SizeMedium}">
+        <BoxView.HeightRequest>
+          <OnPlatform
+                        x:TypeArguments="x:Double"
+                        iOS="40"
+                        Android="30"
+                        WinPhone="60" />
+        </BoxView.HeightRequest>
+      </BoxView>
+      <BoxView  HorizontalOptions="Center" VerticalOptions="Center" BackgroundColor="Red" WidthRequest="{StaticResource SizeLarge}">
+
+      </BoxView>
+    </StackLayout>
+  </local:TestContentPage.Content>
+</local:TestContentPage>
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla39636.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla39636.xaml.cs
new file mode 100644 (file)
index 0000000..45e2c8c
--- /dev/null
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+using Xamarin.Forms;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Xaml;
+
+#if UITEST
+using Xamarin.Forms.Core.UITests;
+using Xamarin.UITest;
+using NUnit.Framework;
+#endif
+
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Bugzilla, 39636, "Cannot use XamlC with OnPlatform in resources, it throws System.InvalidCastException", PlatformAffected.All)]
+       #if APP
+       [XamlCompilation(XamlCompilationOptions.Compile)]
+       #endif
+       public partial class Bugzilla39636 : TestContentPage
+       {
+               public Bugzilla39636 ()
+               {
+#if APP
+                       InitializeComponent ();
+#endif
+               }
+
+               protected override void Init()
+               {
+
+               }
+
+#if UITEST
+               [Test]
+               public void DoesNotCrash()
+               {
+                       RunningApp.WaitForElement(q => q.Text("Success"));
+               }
+#endif
+       }
+}
index 93de60b..3d745c3 100644 (file)
       <DependentUpon>Bugzilla39463.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Compile Include="$(MSBuildThisFileDirectory)Bugzilla39636.xaml.cs">
+      <DependentUpon>Bugzilla39636.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla39702.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)CarouselAsync.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Bugzilla34561.cs" />
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
   </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla39636.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
+    </EmbeddedResource>
+  </ItemGroup>
 </Project>
\ No newline at end of file
index f17218c..7562fc2 100644 (file)
     <Compile Include="PlatformTests\DisplayAlertUITestsAndroid.cs" />
     <Compile Include="..\Xamarin.Forms.Core.iOS.UITests\Tests\AppearingUITests.cs">
       <Link>Tests\AppearingUITests.cs</Link>
-       </Compile>
+    </Compile>
     <Compile Include="..\Xamarin.Forms.Core.iOS.UITests\Tests\AutomationIDUITests.cs">
       <Link>Tests\AutomationIDUITests.cs</Link>
     </Compile>
       <Project>{67f9d3a8-f71e-4428-913f-c37ae82cdb24}</Project>
       <Name>Xamarin.Forms.Platform</Name>
     </ProjectReference>
+    <ProjectReference Include="..\Xamarin.Forms.Xaml\Xamarin.Forms.Xaml.csproj">
+      <Project>{9DB2F292-8034-4E06-89AD-98BBDA4306B9}</Project>
+      <Name>Xamarin.Forms.Xaml</Name>
+    </ProjectReference>
   </ItemGroup>
   <ItemGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
index e5a7aef..4f1465d 100644 (file)
@@ -1,4 +1,5 @@
 using System;
+using System.Reflection;
 
 namespace Xamarin.Forms.Xaml
 {
@@ -32,13 +33,35 @@ namespace Xamarin.Forms.Xaml
                                        continue;
                                object res;
                                if (ve.Resources.TryGetValue(Key, out res))
-                                       return res;
+                               {
+                                       return ConvertCompiledOnPlatform(res);
+                               }
                        }
                        if (Application.Current != null && Application.Current.Resources != null &&
                            Application.Current.Resources.ContainsKey(Key))
-                               return Application.Current.Resources[Key];
+                       {
+                               var resource = Application.Current.Resources[Key];
+
+                               return ConvertCompiledOnPlatform(resource);
+                       }
+
+                       throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
+               }
+
+               static object ConvertCompiledOnPlatform(object resource)
+               {
+                       var actualType = resource.GetType();
+                       if (actualType.GetTypeInfo().IsGenericType && actualType.GetGenericTypeDefinition() == typeof(OnPlatform<>))
+                       {
+                               // If we're accessing OnPlatform via a StaticResource in compiled XAML 
+                               // we'll have to handle the cast to the target type manually 
+                               // (Normally the compiled XAML handles this by calling `implicit` explicitly,
+                               // but it doesn't know to do that when it's using a static resource)
+                               var method = actualType.GetRuntimeMethod("op_Implicit", new[] { actualType });
+                               resource = method.Invoke(resource, new[] { resource });
+                       }
 
-                       throw new XamlParseException(string.Format("StaticResource not found for key {0}", Key), xmlLineInfo);
+                       return resource;
                }
        }
 }
\ No newline at end of file