[X] internal CreateFromXaml () (#77)
authorStephane Delcroix <stephane@delcroix.org>
Tue, 12 Apr 2016 16:46:39 +0000 (18:46 +0200)
committerJason Smith <jason.smith@xamarin.com>
Tue, 12 Apr 2016 16:46:39 +0000 (09:46 -0700)
Xamarin.Forms.Build.Tasks/ILRootNode.cs
Xamarin.Forms.Xaml.UnitTests/TypeConverterTestsLegacy.cs
Xamarin.Forms.Xaml.UnitTests/Xamarin.Forms.Xaml.UnitTests.csproj
Xamarin.Forms.Xaml.UnitTests/XamlLoaderCreateTests.cs [new file with mode: 0644]
Xamarin.Forms.Xaml/ApplyPropertiesVisitor.cs
Xamarin.Forms.Xaml/CreateValuesVisitor.cs
Xamarin.Forms.Xaml/HydratationContext.cs
Xamarin.Forms.Xaml/XamlLoader.cs
Xamarin.Forms.Xaml/XamlNode.cs

index b50d620..1c59cd3 100644 (file)
@@ -5,7 +5,7 @@ namespace Xamarin.Forms.Build.Tasks
 {
        class ILRootNode : RootNode
        {
-               public ILRootNode(XmlType xmlType, TypeReference typeReference) : base(xmlType)
+               public ILRootNode(XmlType xmlType, TypeReference typeReference) : base(xmlType, null)
                {
                        TypeReference = typeReference;
                }
index 9d5051f..4066bb2 100644 (file)
@@ -123,7 +123,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        var bindable = new Bindable ();
 
                        Assert.IsNull (bindable.Baz);
-                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable) {
+                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) {
                                Properties = {
                                        { new XmlName (null, "Baz"), node },
                                }
@@ -142,7 +142,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        var bindable = new Bindable ();
 
                        Assert.IsNull (bindable.Baz);
-                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable) {
+                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) {
                                Properties = {
                                        { new XmlName (null, "Baz"), node },
                                }
@@ -159,7 +159,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        var bindable = new Bindable ();
 
                        Assert.IsNull (bindable.Foo);
-                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable) {
+                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) {
                                Properties = {
                                        { new XmlName (null, "Foo"), node },
                                }
@@ -180,7 +180,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        var bindable = new Bindable ();
 
                        Assert.IsNull (bindable.Bar);
-                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable) {
+                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) {
                                Properties = {
                                        { new XmlName (null, "Bar"), node },
                                }
@@ -200,7 +200,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        var bindable = new Bindable ();
 
                        Assert.IsNull (Bindable.GetQux (bindable));
-                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable) {
+                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) {
                                Properties = {
                                        { new XmlName ("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable.Qux"), node },
                                }
@@ -220,7 +220,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        var bindable = new Bindable ();
 
                        Assert.IsNull (bindable.FooBar);
-                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable) {
+                       var rootNode = new XamlLoader.RuntimeRootNode (new XmlType("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests","Bindable",null), bindable, null) {
                                Properties = {
                                        { new XmlName (null, "FooBar"), node },
                                }
index ff6ebee..226e8bb 100644 (file)
     <Compile Include="McIgnorable.xaml.cs">
       <DependentUpon>McIgnorable.xaml</DependentUpon>
     </Compile>
+    <Compile Include="XamlLoaderCreateTests.cs" />
   </ItemGroup>
   <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
   <Import Project="..\.nuspec\Xamarin.Forms.Debug.targets" />
diff --git a/Xamarin.Forms.Xaml.UnitTests/XamlLoaderCreateTests.cs b/Xamarin.Forms.Xaml.UnitTests/XamlLoaderCreateTests.cs
new file mode 100644 (file)
index 0000000..a175b57
--- /dev/null
@@ -0,0 +1,38 @@
+using System;
+using NUnit.Framework;
+
+namespace Xamarin.Forms.Xaml.UnitTests
+{
+       [TestFixture]
+       public class XamlLoaderCreateTests
+       {
+               [Test]
+               public void CreateFromXaml ()
+               {
+                       var xaml = @"
+                               <ContentView xmlns=""http://xamarin.com/schemas/2014/forms""
+                                                        xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
+                                                        x:Class=""Xamarin.Forms.Xaml.UnitTests.FOO"">
+                                       <Label Text=""Foo""  x:Name=""label""/>
+                               </ContentView>";
+
+                       var view = XamlLoader.Create (xaml);
+                       Assert.That (view, Is.TypeOf<ContentView> ());
+                       Assert.AreEqual ("Foo", ((Label)((ContentView)view).Content).Text);
+               }
+
+               [Test]
+               public void CreateFromXamlDoesntFailOnMissingEventHandler ()
+               {
+                       var xaml = @"
+                               <Button xmlns=""http://xamarin.com/schemas/2014/forms""
+                                               xmlns:x=""http://schemas.microsoft.com/winfx/2009/xaml""
+                                               Clicked=""handleClick"">
+                               </Button>";
+
+                       Button button = null;
+                       Assert.DoesNotThrow (() => button = XamlLoader.Create (xaml, true) as Button);
+                       Assert.NotNull (button);
+               }
+       }
+}
\ No newline at end of file
index e013a74..8978f4f 100644 (file)
@@ -307,19 +307,25 @@ namespace Xamarin.Forms.Xaml
                        if (eventInfo != null && value is string)
                        {
                                var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value);
-                               if (methodInfo == null)
-                               {
-                                       throw new XamlParseException(string.Format("No method {0} found on type {1}", value, rootElement.GetType()),
-                                               lineInfo);
+                               if (methodInfo == null) {
+                                       var xpe = new XamlParseException (string.Format ("No method {0} found on type {1}", value, rootElement.GetType ()), lineInfo);
+                                       if (context.DoNotThrowOnExceptions) {
+                                               System.Diagnostics.Debug.WriteLine (xpe.Message);
+                                               return;
+                                       } else
+                                               throw xpe;
                                }
-
                                try
                                {
                                        eventInfo.AddEventHandler(xamlelement, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement));
                                }
                                catch (ArgumentException)
                                {
-                                       throw new XamlParseException(string.Format("Method {0} does not have the correct signature", value), lineInfo);
+                                       var xpe = new XamlParseException (string.Format ("Method {0} does not have the correct signature", value), lineInfo);
+                                       if (context.DoNotThrowOnExceptions)
+                                               System.Diagnostics.Debug.WriteLine (xpe.Message);
+                                       else
+                                               throw xpe;
                                }
 
                                return;
@@ -416,7 +422,10 @@ namespace Xamarin.Forms.Xaml
                                }
                        }
 
-                       throw exception;
+                       if (context.DoNotThrowOnExceptions)
+                               System.Diagnostics.Debug.WriteLine (exception.Message);
+                       else
+                               throw exception;
                }
 
                void SetTemplate(ElementTemplate dt, INode node)
index 96af918..d54a36d 100644 (file)
@@ -66,7 +66,7 @@ namespace Xamarin.Forms.Xaml
                                return;
 
                        XamlParseException xpe;
-                       var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement.GetType().GetTypeInfo().Assembly,
+                       var type = XamlParser.GetElementType(node.XmlType, node, Context.RootElement?.GetType().GetTypeInfo().Assembly,
                                out xpe);
                        if (xpe != null)
                                throw xpe;
index befb909..7c1356d 100644 (file)
@@ -18,5 +18,7 @@ namespace Xamarin.Forms.Xaml
                public HydratationContext ParentContext { get; set; }
 
                public BindableObject RootElement { get; set; }
+
+               public bool DoNotThrowOnExceptions { get; set; }
        }
 }
\ No newline at end of file
index 8bf08f6..575f2c7 100644 (file)
@@ -62,23 +62,53 @@ namespace Xamarin.Forms.Xaml
                                                continue;
                                        }
 
-                                       var rootnode = new RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), view);
-
-                                       XamlParser.ParseXaml(rootnode, reader);
+                                       var rootnode = new RuntimeRootNode (new XmlType (reader.NamespaceURI, reader.Name, null), view, (IXmlNamespaceResolver)reader);
+                                       XamlParser.ParseXaml (rootnode, reader);
+                                       Visit (rootnode, new HydratationContext { RootElement = view });
+                                       break;
+                               }
+                       }
+               }
 
-                                       var visitorContext = new HydratationContext { RootElement = view };
+               public static object Create (string xaml, bool doNotThrow = false)
+               {
+                       object inflatedView = null;
+                       using (var reader = XmlReader.Create (new StringReader (xaml))) {
+                               while (reader.Read ()) {
+                                       //Skip until element
+                                       if (reader.NodeType == XmlNodeType.Whitespace)
+                                               continue;
+                                       if (reader.NodeType != XmlNodeType.Element) {
+                                               Debug.WriteLine ("Unhandled node {0} {1} {2}", reader.NodeType, reader.Name, reader.Value);
+                                               continue;
+                                       }
 
-                                       rootnode.Accept(new XamlNodeVisitor((node, parent) => node.Parent = parent), null);
-                                               //set parents for {StaticResource}
-                                       rootnode.Accept(new ExpandMarkupsVisitor(visitorContext), null);
-                                       rootnode.Accept(new NamescopingVisitor(visitorContext), null); //set namescopes for {x:Reference}
-                                       rootnode.Accept(new CreateValuesVisitor(visitorContext), null);
-                                       rootnode.Accept(new RegisterXNamesVisitor(visitorContext), null);
-                                       rootnode.Accept(new FillResourceDictionariesVisitor(visitorContext), null);
-                                       rootnode.Accept(new ApplyPropertiesVisitor(visitorContext, true), null);
+                                       var rootnode = new RuntimeRootNode (new XmlType (reader.NamespaceURI, reader.Name, null), null, (IXmlNamespaceResolver)reader);
+                                       XamlParser.ParseXaml (rootnode, reader);
+                                       var visitorContext = new HydratationContext {
+                                               DoNotThrowOnExceptions = doNotThrow,
+                                       };
+                                       var cvv = new CreateValuesVisitor (visitorContext);
+                                       cvv.Visit ((ElementNode)rootnode, null);
+                                       inflatedView = rootnode.Root = visitorContext.Values [rootnode];
+                                       visitorContext.RootElement = inflatedView as BindableObject;
+
+                                       Visit (rootnode, visitorContext);
                                        break;
                                }
                        }
+                       return inflatedView;
+               }
+
+               static void Visit (RootNode rootnode, HydratationContext visitorContext)
+               {
+                       rootnode.Accept (new XamlNodeVisitor ((node, parent) => node.Parent = parent), null); //set parents for {StaticResource}
+                       rootnode.Accept (new ExpandMarkupsVisitor (visitorContext), null);
+                       rootnode.Accept (new NamescopingVisitor (visitorContext), null); //set namescopes for {x:Reference}
+                       rootnode.Accept (new CreateValuesVisitor (visitorContext), null);
+                       rootnode.Accept (new RegisterXNamesVisitor (visitorContext), null);
+                       rootnode.Accept (new FillResourceDictionariesVisitor (visitorContext), null);
+                       rootnode.Accept (new ApplyPropertiesVisitor (visitorContext, true), null);
                }
 
                static string GetXamlForType(Type type)
@@ -197,12 +227,12 @@ namespace Xamarin.Forms.Xaml
 
                public class RuntimeRootNode : RootNode
                {
-                       public RuntimeRootNode(XmlType xmlType, object root) : base(xmlType)
+                       public RuntimeRootNode(XmlType xmlType, object root, IXmlNamespaceResolver resolver) : base (xmlType, resolver)
                        {
                                Root = root;
                        }
 
-                       public object Root { get; private set; }
+                       public object Root { get; internal set; }
                }
        }
 }
\ No newline at end of file
index 2ef87c1..aa8e6c8 100644 (file)
@@ -178,7 +178,7 @@ namespace Xamarin.Forms.Xaml
 
        internal abstract class RootNode : ElementNode
        {
-               protected RootNode(XmlType xmlType) : base(xmlType, xmlType.NamespaceUri, null)
+               protected RootNode(XmlType xmlType, IXmlNamespaceResolver nsResolver) : base(xmlType, xmlType.NamespaceUri, nsResolver)
                {
                }