[XamlC] Find the real VisualState parent (#2036)

`VisualStateGroupList` can be implicit, and it looks like tht wasn't
tested. This adds a test, and a fix.

 - fixes #2034
This commit is contained in:
Stephane Delcroix 2018-03-08 16:20:25 +01:00 коммит произвёл GitHub
Родитель a70e40d96d
Коммит 8403ef065b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 95 добавлений и 14 удалений

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

@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using Mono.Cecil;
using Mono.Cecil.Cil;
@ -32,27 +33,23 @@ namespace Xamarin.Forms.Core.XamlC
var parts = value.Split('.');
if (parts.Length == 1) {
var parent = node.Parent?.Parent as IElementNode ?? (node.Parent?.Parent as IListNode)?.Parent as IElementNode;
if ((node.Parent as ElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri &&
((node.Parent as ElementNode)?.XmlType.Name == "Setter" || (node.Parent as ElementNode)?.XmlType.Name == "PropertyCondition")) {
if ( (node.Parent as ElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri
&& ( (node.Parent as ElementNode)?.XmlType.Name == nameof(Setter)
|| (node.Parent as ElementNode)?.XmlType.Name == nameof(PropertyCondition))) {
if (parent.XmlType.NamespaceUri == XamlParser.XFUri &&
(parent.XmlType.Name == "Trigger" || parent.XmlType.Name == "DataTrigger" || parent.XmlType.Name == "MultiTrigger" || parent.XmlType.Name == "Style")) {
( parent.XmlType.Name == nameof(Trigger)
|| parent.XmlType.Name == nameof(DataTrigger)
|| parent.XmlType.Name == nameof(MultiTrigger)
|| parent.XmlType.Name == nameof(Style))) {
var ttnode = (parent as ElementNode).Properties [new XmlName("", "TargetType")];
if (ttnode is ValueNode)
typeName = (ttnode as ValueNode).Value as string;
else if (ttnode is IElementNode)
typeName = ((ttnode as IElementNode).CollectionItems.FirstOrDefault() as ValueNode)?.Value as string ?? ((ttnode as IElementNode).Properties [new XmlName("", "TypeName")] as ValueNode)?.Value as string;
} else if (parent.XmlType.NamespaceUri == XamlParser.XFUri && parent.XmlType.Name == "VisualState") {
var current = parent.Parent.Parent.Parent as IElementNode;
if (current.XmlType.NamespaceUri == XamlParser.XFUri && current.XmlType.Name == "Setter") {
// Parent will be a Style, and the type will be that Style's TargetType
typeName =
((current?.Parent as IElementNode)?.Properties[new XmlName("", "TargetType")] as ValueNode)?.Value as string;
} else {
typeName = current.XmlType.Name;
}
} else if (parent.XmlType.NamespaceUri == XamlParser.XFUri && parent.XmlType.Name == nameof(VisualState)) {
typeName = FindTypeNameForVisualState(parent, node);
}
} else if ((node.Parent as ElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri && (node.Parent as ElementNode)?.XmlType.Name == "Trigger")
} else if ((node.Parent as ElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri && (node.Parent as ElementNode)?.XmlType.Name == nameof(Trigger))
typeName = ((node.Parent as ElementNode).Properties [new XmlName("", "TargetType")] as ValueNode).Value as string;
propertyName = parts [0];
} else if (parts.Length == 2) {
@ -73,6 +70,29 @@ namespace Xamarin.Forms.Core.XamlC
return bpRef;
}
static string FindTypeNameForVisualState(IElementNode parent, IXmlLineInfo lineInfo)
{
//1. parent is VisualState, don't check that
//2. check that the VS is in a VSG
if (!(parent.Parent is IElementNode target) || target.XmlType.NamespaceUri != XamlParser.XFUri || target.XmlType.Name != nameof(VisualStateGroup))
throw new XamlParseException($"Expected {nameof(VisualStateGroup)} but found {parent.Parent}", lineInfo);
//3. if the VSG is in a VSGL, skip that as it could be implicit
if ( target.Parent is ListNode
|| ( (target.Parent as IElementNode)?.XmlType.NamespaceUri == XamlParser.XFUri
&& (target.Parent as IElementNode)?.XmlType.Name == nameof(VisualStateGroupList)))
target = target.Parent.Parent as IElementNode;
else
target = target.Parent as IElementNode;
//4. target is now a Setter in a Style, or a VE
if (target.XmlType.NamespaceUri == XamlParser.XFUri && target.XmlType.Name == nameof(Setter))
return ((target?.Parent as IElementNode)?.Properties[new XmlName("", "TargetType")] as ValueNode)?.Value as string;
else
return target.XmlType.Name;
}
public static FieldReference GetBindablePropertyFieldReference(TypeReference typeRef, string propertyName, ModuleDefinition module)
{
TypeReference declaringTypeReference;

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

@ -0,0 +1,21 @@
<?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.Gh2034">
<FlexLayout StyleClass="login-form">
<Label >
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="StrengthStates">
<VisualState x:Name="VeryWeak">
<VisualState.Setters>
<Setter Property="Text" Value="foo"/>
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
</Label>
</FlexLayout>
</ContentPage>

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

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Xamarin.Forms;
namespace Xamarin.Forms.Xaml.UnitTests
{
[XamlCompilation(XamlCompilationOptions.Skip)]
public partial class Gh2034 : ContentPage
{
public Gh2034()
{
InitializeComponent();
}
public Gh2034(bool useCompiledXaml)
{
//this stub will be replaced at compile time
}
[TestFixture]
class Tests
{
[TestCase(true)]
public void Compiles(bool useCompiledXaml)
{
if (!useCompiledXaml)
return;
MockCompiler.Compile(typeof(Gh2034));
Assert.Pass();
}
}
}
}

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

@ -579,6 +579,9 @@
<Compile Include="Issues\Gh1978.xaml.cs">
<DependentUpon>Gh1978.xaml</DependentUpon>
</Compile>
<Compile Include="Issues\Gh2034.xaml.cs">
<DependentUpon>Gh2034.xaml</DependentUpon>
</Compile>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
@ -1036,6 +1039,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
<EmbeddedResource Include="Issues\Gh2034.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />