[Xaml[C]] cast to BindingBase before SetBinding() (#709)

This commit is contained in:
Stephane Delcroix 2017-02-01 17:03:53 +01:00 коммит произвёл GitHub
Родитель ae59382c90
Коммит d598d5efe3
5 изменённых файлов: 76 добавлений и 2 удалений

Просмотреть файл

@ -724,7 +724,7 @@ namespace Xamarin.Forms.Build.Tasks
if (CanAdd(parent, localName, valueNode, context)) if (CanAdd(parent, localName, valueNode, context))
return Add(parent, localName, valueNode, iXmlLineInfo, context); return Add(parent, localName, valueNode, iXmlLineInfo, context);
throw new XamlParseException($"No property, bindable property, or event found for '{localName}'", iXmlLineInfo); throw new XamlParseException($"No property, bindable property, or event found for '{localName}', or mismatching type between value and property.", iXmlLineInfo);
} }
static FieldReference GetBindablePropertyReference(VariableDefinition parent, string namespaceURI, ref string localName, out bool attached, ILContext context, IXmlLineInfo iXmlLineInfo) static FieldReference GetBindablePropertyReference(VariableDefinition parent, string namespaceURI, ref string localName, out bool attached, ILContext context, IXmlLineInfo iXmlLineInfo)
@ -838,6 +838,10 @@ namespace Xamarin.Forms.Build.Tasks
VariableDefinition varValue; VariableDefinition varValue;
if (!context.Variables.TryGetValue(valueNode as IElementNode, out varValue)) if (!context.Variables.TryGetValue(valueNode as IElementNode, out varValue))
return false; return false;
var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(module.Import(typeof(BindingBase)), module);
if (implicitOperator != null)
return true;
return varValue.VariableType.InheritsFromOrImplements(module.Import(typeof(BindingBase))); return varValue.VariableType.InheritsFromOrImplements(module.Import(typeof(BindingBase)));
} }
@ -845,6 +849,7 @@ namespace Xamarin.Forms.Build.Tasks
{ {
var module = context.Body.Method.Module; var module = context.Body.Method.Module;
var varValue = context.Variables [elementNode]; var varValue = context.Variables [elementNode];
var implicitOperator = varValue.VariableType.GetImplicitOperatorTo(module.Import(typeof(BindingBase)), module);
//TODO: check if parent is a BP //TODO: check if parent is a BP
var setBinding = typeof(BindableObject).GetMethod("SetBinding", new [] { typeof(BindableProperty), typeof(BindingBase) }); var setBinding = typeof(BindableObject).GetMethod("SetBinding", new [] { typeof(BindableProperty), typeof(BindingBase) });
@ -852,6 +857,9 @@ namespace Xamarin.Forms.Build.Tasks
yield return Instruction.Create(OpCodes.Ldloc, parent); yield return Instruction.Create(OpCodes.Ldloc, parent);
yield return Instruction.Create(OpCodes.Ldsfld, bpRef); yield return Instruction.Create(OpCodes.Ldsfld, bpRef);
yield return Instruction.Create(OpCodes.Ldloc, varValue); yield return Instruction.Create(OpCodes.Ldloc, varValue);
if (implicitOperator != null)
// IL_000f: call !0 class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<BindingBase>::op_Implicit(class [Xamarin.Forms.Core]Xamarin.Forms.OnPlatform`1<!0>)
yield return Instruction.Create(OpCodes.Call, module.Import(implicitOperator));
yield return Instruction.Create(OpCodes.Callvirt, module.Import(setBinding)); yield return Instruction.Create(OpCodes.Callvirt, module.Import(setBinding));
} }

Просмотреть файл

@ -0,0 +1,12 @@
<?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.Bz44213">
<Label x:Name="label">
<Label.Text>
<OnPlatform x:TypeArguments="BindingBase" Android="{Binding Bar}">
<OnPlatform.iOS>
<Binding Path="Foo"/>
</OnPlatform.iOS>
</OnPlatform>
</Label.Text>
</Label>
</ContentPage>

Просмотреть файл

@ -0,0 +1,48 @@
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
public partial class Bz44213 : ContentPage
{
public Bz44213()
{
InitializeComponent();
}
public Bz44213(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 BindingInOnPlatform(bool useCompiledXaml)
{
((MockPlatformServices)Device.PlatformServices).RuntimePlatform = Device.iOS;
var p = new Bz44213(useCompiledXaml);
p.BindingContext = new { Foo = "Foo", Bar = "Bar" };
Assert.AreEqual("Foo", p.label.Text);
((MockPlatformServices)Device.PlatformServices).RuntimePlatform = Device.Android;
p = new Bz44213(useCompiledXaml);
p.BindingContext = new { Foo = "Foo", Bar = "Bar" };
Assert.AreEqual("Bar", p.label.Text);
}
}
}
}

Просмотреть файл

@ -424,6 +424,9 @@
<Compile Include="Issues\Bz43733.xaml.cs"> <Compile Include="Issues\Bz43733.xaml.cs">
<DependentUpon>Bz43733.xaml</DependentUpon> <DependentUpon>Bz43733.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Issues\Bz44213.xaml.cs">
<DependentUpon>Bz44213.xaml</DependentUpon>
</Compile>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" /> <Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
@ -769,6 +772,9 @@
<EmbeddedResource Include="Issues\Bz43733.xaml"> <EmbeddedResource Include="Issues\Bz43733.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator> <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Issues\Bz44213.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

Просмотреть файл

@ -361,7 +361,7 @@ namespace Xamarin.Forms.Xaml
exception = null; exception = null;
var elementType = element.GetType(); var elementType = element.GetType();
var binding = value as BindingBase; var binding = value.ConvertTo(typeof(BindingBase),pinfoRetriever:null,serviceProvider:null) as BindingBase;
var bindable = element as BindableObject; var bindable = element as BindableObject;
var nativeBindingService = DependencyService.Get<INativeBindingService>(); var nativeBindingService = DependencyService.Get<INativeBindingService>();