[Xaml[C]] Do not instantiate DataTemplate Content at parsing time (#683)

* [Xaml] rename VisitChildrenFirst

* [Xaml] rework SkipChildren in XamlNode

* [Xaml] fix 45179

* fix
This commit is contained in:
Stephane Delcroix 2017-01-25 14:47:27 +01:00 коммит произвёл GitHub
Родитель ebb24b7edd
Коммит f30aa8ae2c
21 изменённых файлов: 235 добавлений и 258 удалений

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

@ -21,20 +21,11 @@ namespace Xamarin.Forms.Build.Tasks
ModuleDefinition Module { get; }
public bool VisitChildrenFirst
{
get { return true; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => false;
public bool StopOnDataTemplate
{
get { return true; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public void Visit(ValueNode node, INode parentNode)
{

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

@ -24,20 +24,10 @@ namespace Xamarin.Forms.Build.Tasks
ILContext Context { get; }
public bool VisitChildrenFirst
{
get { return true; }
}
public bool StopOnDataTemplate
{
get { return false; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
public bool StopOnDataTemplate => false;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => true;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -13,20 +13,10 @@ namespace Xamarin.Forms.Build.Tasks
public ILContext Context { get; }
public bool VisitChildrenFirst
{
get { return false; }
}
public bool StopOnDataTemplate
{
get { return true; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => false;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -16,20 +16,10 @@ namespace Xamarin.Forms.Build.Tasks
ILContext Context { get; }
public bool VisitChildrenFirst
{
get { return false; }
}
public bool StopOnDataTemplate
{
get { return true; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => false;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -37,8 +37,9 @@ namespace Xamarin.Forms.Build.Tasks
public ILContext Context { get; }
public bool StopOnResourceDictionary { get; }
public bool VisitChildrenFirst { get; } = true;
public bool StopOnDataTemplate { get; } = true;
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
public bool StopOnDataTemplate => true;
public bool VisitNodeOnDataTemplate => true;
ModuleDefinition Module { get; }
@ -88,6 +89,11 @@ namespace Xamarin.Forms.Build.Tasks
if ((propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) && skips.Contains(propertyName))
return;
if (propertyName == XmlName._CreateContent) {
SetDataTemplate((IElementNode)parentNode, node, Context, node);
return;
}
//if this node is an IMarkupExtension, invoke ProvideValue() and replace the variable
var vardef = Context.Variables[node];
var vardefref = new VariableDefinitionReference(vardef);
@ -114,11 +120,8 @@ namespace Xamarin.Forms.Build.Tasks
return;
if (parentNode is IElementNode && ((IElementNode)parentNode).SkipProperties.Contains (propertyName))
return;
if (propertyName == XmlName._CreateContent)
SetDataTemplate((IElementNode)parentNode, node, Context, node);
else
Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
Context.IL.Append(SetPropertyValue(Context.Variables[(IElementNode)parentNode], propertyName, node, Context, node));
}
else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode)
{

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

@ -1,6 +1,5 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
@ -20,26 +19,15 @@ namespace Xamarin.Forms.Build.Tasks
ModuleDefinition Module { get; }
public bool VisitChildrenFirst
{
get { return false; }
}
public bool StopOnDataTemplate
{
get { return true; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => false;
public void Visit(ValueNode node, INode parentNode)
{
XmlName propertyName;
if (!SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName))
{
if (!SetPropertiesVisitor.TryGetPropertyName(node, parentNode, out propertyName)) {
if (!IsCollectionItem(node, parentNode))
return;
string contentProperty;

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

@ -4,6 +4,7 @@ using System.Collections.Generic;
using Xamarin.Forms;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
@ -22,6 +23,18 @@ namespace Xamarin.Forms.Xaml.UnitTests
[TestFixture]
class Tests
{
[SetUp]
public void Setup()
{
Device.PlatformServices = new MockPlatformServices();
}
[TearDown]
public void TearDown()
{
Device.PlatformServices = null;
}
[TestCase(true)]
[TestCase(false)]
public void DataTemplateInResourceDictionaries (bool useCompiledXaml)

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

@ -4,6 +4,7 @@ using System.Collections.Generic;
using Xamarin.Forms;
using NUnit.Framework;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
@ -26,6 +27,18 @@ namespace Xamarin.Forms.Xaml.UnitTests
[TestFixture]
class Tests
{
[SetUp]
public void Setup()
{
Device.PlatformServices = new MockPlatformServices();
}
[TearDown]
public void TearDown()
{
Device.PlatformServices = null;
}
[TestCase(true)]
[TestCase(false)]
public void BaseClassIdentifiersAreValidForResources (bool useCompiledXaml)

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

@ -0,0 +1,14 @@
<?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.Bz45179">
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="dt0">
<local:Bz45179_0/>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
</ContentPage>

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

@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using Xamarin.Forms;
using Xamarin.Forms.Core.UnitTests;
namespace Xamarin.Forms.Xaml.UnitTests
{
public class Bz45179_0 : ContentView {
public static int creator_count;
public Bz45179_0()
{
creator_count++;
}
}
public partial class Bz45179 : ContentPage
{
public Bz45179()
{
InitializeComponent();
}
public Bz45179(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 DTDoNotInstantiateTheirContent(bool useCompiledXaml)
{
Bz45179_0.creator_count = 0;
Assume.That(Bz45179_0.creator_count, Is.EqualTo(0));
var page = new Bz45179(useCompiledXaml);
Assert.That(Bz45179_0.creator_count, Is.EqualTo(0));
}
}
}
}

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

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

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

@ -35,15 +35,10 @@ namespace Xamarin.Forms.Xaml
HydratationContext Context { get; }
public bool VisitChildrenFirst {
get { return true; }
}
public bool StopOnDataTemplate {
get { return true; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary { get; }
public bool VisitNodeOnDataTemplate => true;
public void Visit(ValueNode node, INode parentNode)
{
@ -81,6 +76,15 @@ namespace Xamarin.Forms.Xaml
public void Visit(ElementNode node, INode parentNode)
{
var propertyName = XmlName.Empty;
if (TryGetPropertyName(node, parentNode, out propertyName) && propertyName == XmlName._CreateContent){
var s0 = Values[parentNode];
if (s0 is ElementTemplate) {
SetTemplate(s0 as ElementTemplate, node);
return;
}
}
var value = Values [node];
var parentElement = parentNode as IElementNode;
var markupExtension = value as IMarkupExtension;
@ -96,7 +100,7 @@ namespace Xamarin.Forms.Xaml
value = valueProvider.ProvideValue(serviceProvider);
}
XmlName propertyName = XmlName.Empty;
propertyName = XmlName.Empty;
//Simplify ListNodes with single elements
var pList = parentNode as ListNode;
@ -113,11 +117,7 @@ namespace Xamarin.Forms.Xaml
return;
var source = Values [parentNode];
if (propertyName == XmlName._CreateContent && source is ElementTemplate)
SetTemplate(source as ElementTemplate, node);
else
SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
} else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
// Collection element, implicit content, or implicit collection element.
string contentProperty;

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

@ -23,20 +23,10 @@ namespace Xamarin.Forms.Xaml
HydratationContext Context { get; }
public bool VisitChildrenFirst
{
get { return true; }
}
public bool StopOnDataTemplate
{
get { return true; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => false;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -28,20 +28,10 @@ namespace Xamarin.Forms.Xaml
HydratationContext Context { get; }
public bool VisitChildrenFirst
{
get { return true; }
}
public bool StopOnDataTemplate
{
get { return false; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
public bool StopOnDataTemplate => false;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => true;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -20,20 +20,10 @@ namespace Xamarin.Forms.Xaml
get { return Context.Values; }
}
public bool VisitChildrenFirst
{
get { return false; }
}
public bool StopOnDataTemplate
{
get { return true; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => false;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -34,7 +34,7 @@ namespace Xamarin.Forms.Xaml
}
if (resource == null && (Application.Current == null || Application.Current.Resources == null ||
!Application.Current.Resources.TryGetMergedValue(Key, out resource)))
throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
throw new XamlParseException($"StaticResource not found for key {Key}", xmlLineInfo);
var bp = valueProvider.TargetProperty as BindableProperty;
var pi = valueProvider.TargetProperty as PropertyInfo;

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

@ -14,20 +14,10 @@ namespace Xamarin.Forms.Xaml
Dictionary<INode, object> Values { get; set; }
public bool VisitChildrenFirst
{
get { return false; }
}
public bool StopOnDataTemplate
{
get { return false; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => false;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => true;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -5,17 +5,10 @@ namespace Xamarin.Forms.Xaml
{
class PruneIgnoredNodesVisitor : IXamlNodeVisitor
{
public bool StopOnDataTemplate {
get { return false; }
}
public bool StopOnResourceDictionary {
get { return false; }
}
public bool VisitChildrenFirst {
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => false;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => true;
public void Visit(ElementNode node, INode parentNode)
{

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

@ -12,20 +12,10 @@ namespace Xamarin.Forms.Xaml
Dictionary<INode, object> Values { get; }
public bool VisitChildrenFirst
{
get { return false; }
}
public bool StopOnDataTemplate
{
get { return true; }
}
public bool StopOnResourceDictionary
{
get { return false; }
}
public TreeVisitingMode VisitingMode => TreeVisitingMode.TopDown;
public bool StopOnDataTemplate => true;
public bool StopOnResourceDictionary => false;
public bool VisitNodeOnDataTemplate => false;
public void Visit(ValueNode node, INode parentNode)
{

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

@ -1,4 +1,3 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
@ -7,36 +6,30 @@ using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Xaml
{
internal interface INode
interface INode
{
List<string> IgnorablePrefixes { get; set; }
IXmlNamespaceResolver NamespaceResolver { get; }
INode Parent { get; set; }
void Accept(IXamlNodeVisitor visitor, INode parentNode);
INode Clone();
}
internal interface IValueNode : INode
interface IValueNode : INode
{
}
internal interface IElementNode : INode, IListNode
interface IElementNode : INode, IListNode
{
Dictionary<XmlName, INode> Properties { get; }
List<XmlName> SkipProperties { get; }
INameScope Namescope { get; }
XmlType XmlType { get; }
string NamespaceURI { get; }
}
internal interface IListNode : INode
interface IListNode : INode
{
List<INode> CollectionItems { get; }
}
@ -56,7 +49,7 @@ namespace Xamarin.Forms.Xaml
public IList<XmlType> TypeArguments { get; }
}
internal abstract class BaseNode : IXmlLineInfo, INode
abstract class BaseNode : IXmlLineInfo, INode
{
protected BaseNode(IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
{
@ -66,27 +59,19 @@ namespace Xamarin.Forms.Xaml
}
public IXmlNamespaceResolver NamespaceResolver { get; }
public abstract void Accept(IXamlNodeVisitor visitor, INode parentNode);
public INode Parent { get; set; }
public List<string> IgnorablePrefixes { get; set; }
public bool HasLineInfo()
{
return LineNumber >= 0 && LinePosition >= 0;
}
public int LineNumber { get; set; }
public int LinePosition { get; set; }
public bool HasLineInfo() => LineNumber >= 0 && LinePosition >= 0;
public abstract void Accept(IXamlNodeVisitor visitor, INode parentNode);
public abstract INode Clone();
}
[DebuggerDisplay("{Value}")]
internal class ValueNode : BaseNode, IValueNode
class ValueNode : BaseNode, IValueNode
{
public ValueNode(object value, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
: base(namespaceResolver, linenumber, lineposition)
@ -101,19 +86,15 @@ namespace Xamarin.Forms.Xaml
visitor.Visit(this, parentNode);
}
public override INode Clone()
{
return new ValueNode(Value, NamespaceResolver, LineNumber, LinePosition) {
IgnorablePrefixes = IgnorablePrefixes
};
}
public override INode Clone() => new ValueNode(Value, NamespaceResolver, LineNumber, LinePosition) {
IgnorablePrefixes = IgnorablePrefixes
};
}
[DebuggerDisplay("{MarkupString}")]
internal class MarkupNode : BaseNode, IValueNode
class MarkupNode : BaseNode, IValueNode
{
public MarkupNode(string markupString, IXmlNamespaceResolver namespaceResolver, int linenumber = -1,
int lineposition = -1)
public MarkupNode(string markupString, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
: base(namespaceResolver, linenumber, lineposition)
{
MarkupString = markupString;
@ -126,15 +107,13 @@ namespace Xamarin.Forms.Xaml
visitor.Visit(this, parentNode);
}
public override INode Clone()
{
return new MarkupNode(MarkupString, NamespaceResolver, LineNumber, LinePosition) {
IgnorablePrefixes = IgnorablePrefixes
};
}
public override INode Clone() => new MarkupNode(MarkupString, NamespaceResolver, LineNumber, LinePosition) {
IgnorablePrefixes = IgnorablePrefixes
};
}
internal class ElementNode : BaseNode, IValueNode, IElementNode
[DebuggerDisplay("{XmlType.Name}")]
class ElementNode : BaseNode, IValueNode, IElementNode
{
public ElementNode(XmlType type, string namespaceURI, IXmlNamespaceResolver namespaceResolver, int linenumber = -1,
int lineposition = -1)
@ -148,48 +127,48 @@ namespace Xamarin.Forms.Xaml
}
public Dictionary<XmlName, INode> Properties { get; }
public List<XmlName> SkipProperties { get; }
public List<INode> CollectionItems { get; }
public XmlType XmlType { get; }
public string NamespaceURI { get; }
public INameScope Namescope { get; set; }
public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
{
if (!visitor.VisitChildrenFirst)
if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.TopDown)
visitor.Visit(this, parentNode);
if ((!visitor.StopOnDataTemplate || !IsDataTemplate(this, parentNode)) &&
(!visitor.StopOnResourceDictionary || !IsResourceDictionary(this, parentNode)))
{
if (!SkipChildren(visitor, parentNode)) {
foreach (var node in Properties.Values.ToList())
node.Accept(visitor, this);
foreach (var node in CollectionItems)
node.Accept(visitor, this);
}
if (visitor.VisitChildrenFirst)
if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.BottomUp)
visitor.Visit(this, parentNode);
}
internal static bool IsDataTemplate(INode node, INode parentNode)
bool IsDataTemplate(INode parentNode)
{
var parentElement = parentNode as IElementNode;
INode createContent;
if (parentElement != null && parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
createContent == node)
if (parentElement != null &&
parentElement.Properties.TryGetValue(XmlName._CreateContent, out createContent) &&
createContent == this)
return true;
return false;
}
internal static bool IsResourceDictionary(INode node, INode parentNode)
{
var enode = node as ElementNode;
return enode.XmlType.Name == "ResourceDictionary";
}
bool IsResourceDictionary() => XmlType.Name == "ResourceDictionary";
protected bool SkipChildren(IXamlNodeVisitor visitor, INode parentNode) =>
(visitor.StopOnDataTemplate && IsDataTemplate(parentNode)) ||
(visitor.StopOnResourceDictionary && IsResourceDictionary());
protected bool SkipVisitNode(IXamlNodeVisitor visitor, INode parentNode) =>
!visitor.VisitNodeOnDataTemplate && IsDataTemplate(parentNode);
public override INode Clone()
{
@ -206,7 +185,7 @@ namespace Xamarin.Forms.Xaml
}
}
internal abstract class RootNode : ElementNode
abstract class RootNode : ElementNode
{
protected RootNode(XmlType xmlType, IXmlNamespaceResolver nsResolver) : base(xmlType, xmlType.NamespaceUri, nsResolver)
{
@ -214,40 +193,39 @@ namespace Xamarin.Forms.Xaml
public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
{
if (!visitor.VisitChildrenFirst)
if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.TopDown)
visitor.Visit(this, parentNode);
if ((!visitor.StopOnDataTemplate || !IsDataTemplate(this, parentNode)) &&
(!visitor.StopOnResourceDictionary || !IsResourceDictionary(this, parentNode)))
{
if (!SkipChildren(visitor, parentNode)) {
foreach (var node in Properties.Values.ToList())
node.Accept(visitor, this);
foreach (var node in CollectionItems)
node.Accept(visitor, this);
}
if (visitor.VisitChildrenFirst)
if (!SkipVisitNode(visitor, parentNode) && visitor.VisitingMode == TreeVisitingMode.BottomUp)
visitor.Visit(this, parentNode);
}
}
internal class ListNode : BaseNode, IListNode, IValueNode
class ListNode : BaseNode, IListNode, IValueNode
{
public ListNode(IList<INode> nodes, IXmlNamespaceResolver namespaceResolver, int linenumber = -1,
int lineposition = -1) : base(namespaceResolver, linenumber, lineposition)
public ListNode(IList<INode> nodes, IXmlNamespaceResolver namespaceResolver, int linenumber = -1, int lineposition = -1)
: base(namespaceResolver, linenumber, lineposition)
{
CollectionItems = nodes.ToList();
}
public XmlName XmlName { get; set; }
public List<INode> CollectionItems { get; set; }
public override void Accept(IXamlNodeVisitor visitor, INode parentNode)
{
if (!visitor.VisitChildrenFirst)
if (visitor.VisitingMode == TreeVisitingMode.TopDown)
visitor.Visit(this, parentNode);
foreach (var node in CollectionItems)
node.Accept(visitor, this);
if (visitor.VisitChildrenFirst)
if (visitor.VisitingMode == TreeVisitingMode.BottomUp)
visitor.Visit(this, parentNode);
}
@ -262,12 +240,11 @@ namespace Xamarin.Forms.Xaml
}
}
internal static class INodeExtensions
static class INodeExtensions
{
public static bool SkipPrefix(this INode node, string prefix)
{
do
{
do {
if (node.IgnorablePrefixes != null && node.IgnorablePrefixes.Contains(prefix))
return true;
node = node.Parent;

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

@ -2,12 +2,11 @@
namespace Xamarin.Forms.Xaml
{
internal interface IXamlNodeVisitor
interface IXamlNodeVisitor
{
bool VisitChildrenFirst { get; }
TreeVisitingMode VisitingMode { get; }
bool StopOnDataTemplate { get; }
bool VisitNodeOnDataTemplate { get; }
bool StopOnResourceDictionary { get; }
void Visit(ValueNode node, INode parentNode);
@ -17,22 +16,27 @@ namespace Xamarin.Forms.Xaml
void Visit(ListNode node, INode parentNode);
}
internal class XamlNodeVisitor : IXamlNodeVisitor
enum TreeVisitingMode {
TopDown,
BottomUp
}
class XamlNodeVisitor : IXamlNodeVisitor
{
readonly Action<INode, INode> action;
public XamlNodeVisitor(Action<INode, INode> action, bool visitChildrenFirst = false, bool stopOnDataTemplate = false)
public XamlNodeVisitor(Action<INode, INode> action, TreeVisitingMode visitingMode = TreeVisitingMode.TopDown, bool stopOnDataTemplate = false, bool visitNodeOnDataTemplate = true)
{
this.action = action;
VisitChildrenFirst = visitChildrenFirst;
VisitingMode = visitingMode;
StopOnDataTemplate = stopOnDataTemplate;
VisitNodeOnDataTemplate = visitNodeOnDataTemplate;
}
public bool VisitChildrenFirst { get; }
public TreeVisitingMode VisitingMode { get; }
public bool StopOnDataTemplate { get; }
public bool StopOnResourceDictionary { get; private set; }
public bool VisitNodeOnDataTemplate { get; }
public void Visit(ValueNode node, INode parentNode)
{