[Xaml] do not set properties with private setters (#717)
authorStephane Delcroix <stephane@delcroix.org>
Thu, 2 Feb 2017 14:28:59 +0000 (15:28 +0100)
committerKangho Hur <kangho.hur@samsung.com>
Fri, 24 Mar 2017 04:18:57 +0000 (13:18 +0900)
Xamarin.Forms.Xaml.UnitTests/Issues/Bz44216.xaml [new file with mode: 0644]
Xamarin.Forms.Xaml.UnitTests/Issues/Bz44216.xaml.cs [new file with mode: 0644]
Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs

diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Bz44216.xaml b/Xamarin.Forms.Xaml.UnitTests/Issues/Bz44216.xaml
new file mode 100644 (file)
index 0000000..fd0cfb4
--- /dev/null
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
+       xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
+       xmlns:local="clr-namespace:Xamarin.Forms.Xaml.UnitTests"
+       x:Class="Xamarin.Forms.Xaml.UnitTests.Bz44216">
+       <ContentPage.Behaviors>
+               <local:Bz44216Behavior MinLengh="5" />
+       </ContentPage.Behaviors>
+</ContentPage>
diff --git a/Xamarin.Forms.Xaml.UnitTests/Issues/Bz44216.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/Issues/Bz44216.xaml.cs
new file mode 100644 (file)
index 0000000..b6ad87b
--- /dev/null
@@ -0,0 +1,58 @@
+using System;
+using System.Collections.Generic;
+using NUnit.Framework;
+using Xamarin.Forms;
+using Xamarin.Forms.Core.UnitTests;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+       public class Bz44216Behavior : Behavior<ContentPage>
+       {
+               static readonly BindableProperty MinLenghProperty = BindableProperty.Create("MinLengh", typeof(int), typeof(Bz44216Behavior), 1);
+
+               public int MinLengh {
+                       get { return (int)base.GetValue(MinLenghProperty); }
+                       private set { base.SetValue(MinLenghProperty, value > 0 ? value : 1); }
+               }
+       }
+
+       [XamlCompilation(XamlCompilationOptions.Skip)]
+       public partial class Bz44216 : ContentPage
+       {
+               public Bz44216()
+               {
+                       InitializeComponent();
+               }
+
+               public Bz44216(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(true)]
+                       [TestCase(false)]
+                       public void DonSetValueOnPrivateBP(bool useCompiledXaml)
+                       {
+                               if (useCompiledXaml)
+                                       Assert.Throws(new XamlParseExceptionConstraint(7, 26, s => s.StartsWith("No property,", StringComparison.Ordinal)), () => MockCompiler.Compile(typeof(Bz44216)));
+                               else
+                                       Assert.Throws(new XamlParseExceptionConstraint(7, 26, s=> s.StartsWith("Cannot assign property", StringComparison.Ordinal)), () => new Bz44216(useCompiledXaml));
+                       }
+               }
+       }
+}
index 3ea1d1c..833d5d9 100644 (file)
@@ -297,7 +297,7 @@ namespace Xamarin.Forms.Xaml
                                return;
 
                        //If we can assign that value to a normal property, let's do it
-                       if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, out xpe))
+                       if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, context, out xpe))
                                return;
 
                        //If it's an already initialized property, add to it
@@ -423,7 +423,7 @@ namespace Xamarin.Forms.Xaml
                        return false;
                }
 
-               static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, out Exception exception)
+               static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydratationContext context, out Exception exception)
                {
                        exception = null;
 
@@ -433,6 +433,9 @@ namespace Xamarin.Forms.Xaml
                        if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null)
                                return false;
 
+                       if (!IsVisibleFrom(setter, context.RootElement))
+                               return false;
+
                        object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider);
                        if (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue))
                                return false;
@@ -441,6 +444,19 @@ namespace Xamarin.Forms.Xaml
                        return true;
                }
 
+               static bool IsVisibleFrom(MethodInfo setter, object rootElement)
+               {
+                       if (setter.IsPublic)
+                               return true;
+                       if (setter.IsPrivate && setter.DeclaringType == rootElement.GetType())
+                               return true;
+                       if ((setter.IsAssembly || setter.IsFamilyOrAssembly) && setter.DeclaringType.AssemblyQualifiedName == rootElement.GetType().AssemblyQualifiedName)
+                               return true;
+                       if (setter.IsFamily && setter.DeclaringType.IsAssignableFrom(rootElement.GetType()))
+                               return true;
+                       return false;
+               }
+
                static bool TryAddToProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, out Exception exception)
                {
                        exception = null;