diff options
author | Stephane Delcroix <stephane@delcroix.org> | 2016-12-04 22:08:11 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-04 22:08:11 +0100 |
commit | 39f2deb5e04886374e720013782c751a4bb7675d (patch) | |
tree | 64f2df7230760c26533730e73821a6dc5c7607da | |
parent | fb76107f4f3294a9d32c6983bc742ce8dff60cd8 (diff) | |
download | xamarin-forms-39f2deb5e04886374e720013782c751a4bb7675d.tar.gz xamarin-forms-39f2deb5e04886374e720013782c751a4bb7675d.tar.bz2 xamarin-forms-39f2deb5e04886374e720013782c751a4bb7675d.zip |
[Xaml] support arrays as x:Arguments (#545)
* [Xaml] port some FactoryMethod tests to XamlC
* [Xaml] support array parameters in factory ctors
* [XamlC] support arrays as x:Arguments
* fix build
16 files changed, 226 insertions, 75 deletions
diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ArrayExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ArrayExtension.cs new file mode 100644 index 00000000..06261147 --- /dev/null +++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ArrayExtension.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using Xamarin.Forms.Xaml; + +namespace Xamarin.Forms.Build.Tasks +{ + class ArrayExtension : ICompiledMarkupExtension + { + public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference memberRef) + { + var typeNode = node.Properties[new XmlName("", "Type")] as IElementNode; + var typeTypeRef = context.TypeExtensions[typeNode]; + var n = node.CollectionItems.Count; + + var instructions = new List<Instruction>(); + instructions.Add(Instruction.Create(OpCodes.Ldc_I4, n)); + instructions.Add(Instruction.Create(OpCodes.Newarr, typeTypeRef)); + + memberRef = typeTypeRef.MakeArrayType(); + for (var i = 0; i < n; i++) { + instructions.Add(Instruction.Create(OpCodes.Dup)); + instructions.Add(Instruction.Create(OpCodes.Ldc_I4, i)); + instructions.Add(Instruction.Create(OpCodes.Ldloc, context.Variables[node.CollectionItems[i] as IElementNode])); + instructions.Add(Instruction.Create(OpCodes.Stelem_Ref)); + } + return instructions; + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs index b18d9561..285a536b 100644 --- a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs +++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/ICompiledMarkupExtension.cs @@ -7,6 +7,6 @@ namespace Xamarin.Forms.Build.Tasks { interface ICompiledMarkupExtension { - IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, out TypeReference typeRef); + IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference typeRef); } }
\ No newline at end of file diff --git a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs index 14797c53..014fb827 100644 --- a/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs +++ b/Xamarin.Forms.Build.Tasks/CompiledMarkupExtensions/StaticExtension.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using Mono.Cecil; using Mono.Cecil.Cil; using Xamarin.Forms.Xaml; @@ -11,11 +10,11 @@ namespace Xamarin.Forms.Build.Tasks { class StaticExtension : ICompiledMarkupExtension { - public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, out TypeReference memberRef) + public IEnumerable<Instruction> ProvideValue(IElementNode node, ModuleDefinition module, ILContext context, out TypeReference memberRef) { INode ntype; if (!node.Properties.TryGetValue(new XmlName("", "Member"), out ntype)) - ntype = node.CollectionItems [0]; + ntype = node.CollectionItems[0]; var member = ((ValueNode)ntype).Value as string; if (IsNullOrEmpty(member) || !member.Contains(".")) { diff --git a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs index 4e1372c5..ac530216 100644 --- a/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs +++ b/Xamarin.Forms.Build.Tasks/CreateObjectVisitor.cs @@ -64,7 +64,7 @@ namespace Xamarin.Forms.Build.Tasks if (typeref.FullName == "Xamarin.Forms.Xaml.StaticExtension") { var markupProvider = new StaticExtension(); - var il = markupProvider.ProvideValue(node, Module, out typeref); + var il = markupProvider.ProvideValue(node, Module, Context, out typeref); var vardef = new VariableDefinition(typeref); Context.Variables [node] = vardef; @@ -180,7 +180,6 @@ namespace Xamarin.Forms.Build.Tasks Context.IL.Emit(OpCodes.Initobj, Module.Import(typedef)); } - //if/when we land the compiled converters, those 2 blocks could be greatly simplified if (typeref.FullName == "Xamarin.Forms.Xaml.TypeExtension") { var visitor = new SetPropertiesVisitor(Context); foreach (var cnode in node.Properties.Values.ToList()) @@ -212,6 +211,30 @@ namespace Xamarin.Forms.Build.Tasks Context.Body.Variables.Add(vardefref.VariableDefinition); } } + + if (typeref.FullName == "Xamarin.Forms.Xaml.ArrayExtension") + { + var visitor = new SetPropertiesVisitor(Context); + foreach (var cnode in node.Properties.Values.ToList()) + cnode.Accept(visitor, node); + foreach (var cnode in node.CollectionItems) + cnode.Accept(visitor, node); + + var markupProvider = new ArrayExtension(); + + var il = markupProvider.ProvideValue(node, Module, Context, out typeref); + + vardef = new VariableDefinition(typeref); + Context.Variables[node] = vardef; + Context.Body.Variables.Add(vardef); + + Context.IL.Append(il); + Context.IL.Emit(OpCodes.Stloc, vardef); + + //clean the node as it has been fully exhausted + node.Properties.Remove(new XmlName("","Type")); + node.CollectionItems.Clear(); + } } } @@ -316,8 +339,10 @@ namespace Xamarin.Forms.Build.Tasks static bool IsXaml2009LanguagePrimitive(IElementNode node) { - if (node.NamespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml") - return true; + if (node.NamespaceURI == "http://schemas.microsoft.com/winfx/2009/xaml") { + var n = node.XmlType.Name.Split(':') [1]; + return n != "Array"; + } if (node.NamespaceURI != "clr-namespace:System;assembly=mscorlib") return false; var name = node.XmlType.Name.Split(':')[1]; diff --git a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs index d0ccbc59..613b0cc0 100644 --- a/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs +++ b/Xamarin.Forms.Build.Tasks/TypeReferenceExtensions.cs @@ -65,12 +65,9 @@ namespace Xamarin.Forms.Build.Tasks genericArguments = null; var typeDef = typeRef.Resolve(); TypeReference iface; - if ( - (iface = - typeDef.Interfaces.FirstOrDefault( - tr => - tr.FullName.StartsWith(@interface) && tr.IsGenericInstance && (tr as GenericInstanceType).HasGenericArguments)) != - null) + if ((iface = typeDef.Interfaces.FirstOrDefault(tr => + tr.FullName.StartsWith(@interface, StringComparison.Ordinal) && + tr.IsGenericInstance && (tr as GenericInstanceType).HasGenericArguments)) != null) { interfaceReference = iface as GenericInstanceType; genericArguments = (iface as GenericInstanceType).GenericArguments; @@ -89,20 +86,25 @@ namespace Xamarin.Forms.Build.Tasks var arrayInterfaces = new[] { - "System.IEnumerable", + "System.Collections.IEnumerable", "System.Collections.IList", "System.Collections.Collection" }; var arrayGenericInterfaces = new[] { - "System.IEnumerable`1", + "System.Collections.IEnumerable`1", "System.Collections.Generic.IList`1", "System.Collections.Generic.IReadOnlyCollection<T>", "System.Collections.Generic.IReadOnlyList<T>", "System.Collections.Generic.Collection<T>" }; + if (typeRef.IsArray && baseClass.IsArray) { + typeRef = typeRef.Resolve(); + baseClass = baseClass.Resolve(); + } + if (typeRef.IsArray) { var arrayType = typeRef.Resolve(); @@ -112,7 +114,9 @@ namespace Xamarin.Forms.Build.Tasks baseClass.IsGenericInstance && (baseClass as GenericInstanceType).GenericArguments[0].FullName == arrayType.FullName) return true; + return false; } + var typeDef = typeRef.Resolve(); if (typeDef.FullName == baseClass.FullName) return true; diff --git a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj index 515319ef..46d4f23b 100644 --- a/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj +++ b/Xamarin.Forms.Build.Tasks/Xamarin.Forms.Build.Tasks.csproj @@ -100,6 +100,7 @@ <Compile Include="CompiledConverters\RectangleTypeConverter.cs" /> <Compile Include="Logger.cs" /> <Compile Include="XamlTask.cs" /> + <Compile Include="CompiledMarkupExtensions\ArrayExtension.cs" /> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Target Name="AfterBuild"> diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingCtor.xaml b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingCtor.xaml new file mode 100644 index 00000000..f49108cf --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingCtor.xaml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<local:MockView xmlns="http://xamarin.com/schemas/2014/forms" + xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" + xmlns:local="clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests" + x:Class="Xamarin.Forms.Xaml.UnitTests.FactoryMethodMissingCtor"> + <local:MockView.Content> + <local:MockFactory> + <x:Arguments> + <x:Object/> + <x:String>bar</x:String> + <x:Int32>42</x:Int32> + </x:Arguments> + </local:MockFactory> + </local:MockView.Content> +</local:MockView>
\ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingCtor.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingCtor.xaml.cs new file mode 100644 index 00000000..6771edf6 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingCtor.xaml.cs @@ -0,0 +1,35 @@ +using System; +using NUnit.Framework; +using Xamarin.Forms.Core.UnitTests; + +namespace Xamarin.Forms.Xaml.UnitTests +{ + [XamlCompilation(XamlCompilationOptions.Skip)] + public partial class FactoryMethodMissingCtor : MockView + { + public FactoryMethodMissingCtor() + { + InitializeComponent(); + } + + [TestFixture] + public class Tests + { + [SetUp] + public void SetUp() + { + Device.PlatformServices = new MockPlatformServices(); + } + + [TestCase(false)] + [TestCase(true)] + public void Throw(bool useCompiledXaml) + { + if (useCompiledXaml) + Assert.Throws(new XamlParseExceptionConstraint(7, 4), () => MockCompiler.Compile(typeof(FactoryMethodMissingCtor))); + else + Assert.Throws<MissingMethodException>(() => new FactoryMethodMissingCtor()); + } + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingMethod.xaml b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingMethod.xaml new file mode 100644 index 00000000..85e279d1 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingMethod.xaml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<local:MockView + xmlns="http://xamarin.com/schemas/2014/forms" + xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" + xmlns:local="clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests" + x:Class="Xamarin.Forms.Xaml.UnitTests.FactoryMethodMissingMethod"> + <local:MockView.Content> + <local:MockFactory x:FactoryMethod="Factory"> + <x:Arguments> + <x:Object/> + <x:String>bar</x:String> + <x:Int32>42</x:Int32> + </x:Arguments> + </local:MockFactory> + </local:MockView.Content> +</local:MockView>
\ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingMethod.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingMethod.xaml.cs new file mode 100644 index 00000000..ecc40487 --- /dev/null +++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodMissingMethod.xaml.cs @@ -0,0 +1,35 @@ +using System; +using NUnit.Framework; +using Xamarin.Forms.Core.UnitTests; + +namespace Xamarin.Forms.Xaml.UnitTests +{ + [XamlCompilation(XamlCompilationOptions.Skip)] + public partial class FactoryMethodMissingMethod : MockView + { + public FactoryMethodMissingMethod() + { + InitializeComponent(); + } + + [TestFixture] + public class Tests + { + [SetUp] + public void SetUp() + { + Device.PlatformServices = new MockPlatformServices(); + } + + [TestCase(false)] + [TestCase(true)] + public void Throw(bool useCompiledXaml) + { + if (useCompiledXaml) + Assert.Throws(new XamlParseExceptionConstraint(8, 4), () => MockCompiler.Compile(typeof(FactoryMethodMissingMethod))); + else + Assert.Throws<MissingMemberException>(() => new FactoryMethodMissingMethod()); + } + } + } +} diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethodTests.cs b/Xamarin.Forms.Xaml.UnitTests/FactoryMethodTests.cs deleted file mode 100644 index d6ee1886..00000000 --- a/Xamarin.Forms.Xaml.UnitTests/FactoryMethodTests.cs +++ /dev/null @@ -1,53 +0,0 @@ -using System; -using NUnit.Framework; - -using Xamarin.Forms.Core.UnitTests; - -namespace Xamarin.Forms.Xaml.UnitTests -{ - [TestFixture] - public class FactoryMethodTests : BaseTestFixture - { - [Test] - public void ThrowOnMissingCtor () - { - var xaml = @" - <local:MockView - xmlns=""http://xamarin.com/schemas/2014/forms"" - xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml"" - xmlns:local=""clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests"" > - <local:MockView.Content> - <local:MockFactory> - <x:Arguments> - <x:Object/> - <x:String>bar</x:String> - <x:Int32>42</x:Int32> - </x:Arguments> - </local:MockFactory> - </local:MockView.Content> - </local:MockView>"; - Assert.Throws<MissingMethodException> (()=>new MockView ().LoadFromXaml (xaml)); - } - - [Test] - public void ThrowOnMissingMethod () - { - var xaml = @" - <local:MockView - xmlns=""http://xamarin.com/schemas/2014/forms"" - xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml"" - xmlns:local=""clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests"" > - <local:MockView.Content> - <local:MockFactory x:FactoryMethod=""Factory""> - <x:Arguments> - <x:Object/> - <x:String>bar</x:String> - <x:Int32>42</x:Int32> - </x:Arguments> - </local:MockFactory> - </local:MockView.Content> - </local:MockView>"; - Assert.Throws<MissingMemberException> (()=>new MockView ().LoadFromXaml (xaml)); - } - } -} diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml index 5225c7d9..9ff91dea 100644 --- a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml +++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?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" @@ -32,7 +32,7 @@ <local:MockView.Content> <local:MockFactory x:FactoryMethod="ParameterlessFactory"> </local:MockFactory> - </local:MockView.Content> + </local:MockView.Content> </local:MockView> <local:MockView x:Name="v4"> <local:MockView.Content> @@ -68,5 +68,17 @@ <local:MockFactory x:Arguments="{x:Static local:MockxStatic.MockStaticProperty}"/> </local:MockView.Content> </local:MockView> + <local:MockView x:Name="v8"> + <local:MockView.Content> + <local:MockFactory > + <x:Arguments> + <x:Array Type="{x:Type x:Object}"> + <x:String>Foo</x:String> + <x:String>Bar</x:String> + </x:Array> + </x:Arguments> + </local:MockFactory> + </local:MockView.Content> + </local:MockView> </StackLayout> </ContentPage>
\ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs index 9fa4e924..f5790383 100644 --- a/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs +++ b/Xamarin.Forms.Xaml.UnitTests/FactoryMethods.xaml.cs @@ -32,6 +32,11 @@ namespace Xamarin.Forms.Xaml.UnitTests Content = "int ctor " + arg.ToString (); } + public MockFactory(object [] args) + { + Content = string.Join(" ", args); + } + public static MockFactory ParameterlessFactory () { return new MockFactory { @@ -138,6 +143,14 @@ namespace Xamarin.Forms.Xaml.UnitTests var layout = new FactoryMethods(useCompiledXaml); Assert.AreEqual("alternate ctor Property", layout.v7.Content.Content); } + + [TestCase(false)] + [TestCase(true)] + public void TestCtorWithArrayParameter(bool useCompiledXaml) + { + var layout = new FactoryMethods(useCompiledXaml); + Assert.AreEqual("Foo Bar", layout.v8.Content.Content); + } } } }
\ No newline at end of file diff --git a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml index fd11bd5a..5ebc4f4f 100644 --- a/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml +++ b/Xamarin.Forms.Xaml.UnitTests/SetValue.xaml @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="UTF-8"?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" diff --git a/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj b/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj index 9c2776ec..4977edb4 100644 --- a/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj +++ b/Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj @@ -94,7 +94,6 @@ <Compile Include="OnPlatformTests.cs" /> <Compile Include="NullExtensionTests.cs" /> <Compile Include="TypeExtensionTests.cs" /> - <Compile Include="FactoryMethodTests.cs" /> <Compile Include="XamlgTests.cs" /> <Compile Include="Issues\TestCases.cs" /> <Compile Include="Issues\Issue1493.cs" /> @@ -391,6 +390,12 @@ <Compile Include="Issues\Bz47703.xaml.cs"> <DependentUpon>Bz47703.xaml</DependentUpon> </Compile> + <Compile Include="FactoryMethodMissingCtor.xaml.cs"> + <DependentUpon>FactoryMethodMissingCtor.xaml</DependentUpon> + </Compile> + <Compile Include="FactoryMethodMissingMethod.xaml.cs"> + <DependentUpon>FactoryMethodMissingMethod.xaml</DependentUpon> + </Compile> </ItemGroup> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" /> @@ -703,6 +708,12 @@ <EmbeddedResource Include="Issues\Bz47703.xaml"> <Generator>MSBuild:UpdateDesignTimeXaml</Generator> </EmbeddedResource> + <EmbeddedResource Include="FactoryMethodMissingCtor.xaml"> + <Generator>MSBuild:UpdateDesignTimeXaml</Generator> + </EmbeddedResource> + <EmbeddedResource Include="FactoryMethodMissingMethod.xaml"> + <Generator>MSBuild:UpdateDesignTimeXaml</Generator> + </EmbeddedResource> </ItemGroup> <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> diff --git a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs index c2331bf1..817b62c8 100644 --- a/Xamarin.Forms.Xaml/CreateValuesVisitor.cs +++ b/Xamarin.Forms.Xaml/CreateValuesVisitor.cs @@ -107,7 +107,7 @@ namespace Xamarin.Forms.Xaml Values[node] = value; var markup = value as IMarkupExtension; - if (markup != null && (value is TypeExtension || value is StaticExtension)) + if (markup != null && (value is TypeExtension || value is StaticExtension || value is ArrayExtension)) { var serviceProvider = new XamlServiceProvider(node, Context); @@ -119,9 +119,16 @@ namespace Xamarin.Forms.Xaml value = markup.ProvideValue(serviceProvider); + INode xKey; + if (!node.Properties.TryGetValue(XmlName.xKey, out xKey)) + xKey = null; + node.Properties.Clear(); node.CollectionItems.Clear(); + if (xKey != null) + node.Properties.Add(XmlName.xKey, xKey); + Values[node] = value; } |