[X] internal CreateFromXaml () (#77)

This commit is contained in:
Stephane Delcroix 2016-04-12 18:46:39 +02:00 коммит произвёл Jason Smith
Родитель f975a6f2e3
Коммит c92297047c
9 изменённых файлов: 112 добавлений и 32 удалений

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

@ -5,7 +5,7 @@ namespace Xamarin.Forms.Build.Tasks
{ {
class ILRootNode : RootNode class ILRootNode : RootNode
{ {
public ILRootNode(XmlType xmlType, TypeReference typeReference) : base(xmlType) public ILRootNode(XmlType xmlType, TypeReference typeReference) : base(xmlType, null)
{ {
TypeReference = typeReference; TypeReference = typeReference;
} }

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

@ -123,7 +123,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
var bindable = new Bindable (); var bindable = new Bindable ();
Assert.IsNull (bindable.Baz); 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 = { Properties = {
{ new XmlName (null, "Baz"), node }, { new XmlName (null, "Baz"), node },
} }
@ -142,7 +142,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
var bindable = new Bindable (); var bindable = new Bindable ();
Assert.IsNull (bindable.Baz); 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 = { Properties = {
{ new XmlName (null, "Baz"), node }, { new XmlName (null, "Baz"), node },
} }
@ -159,7 +159,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
var bindable = new Bindable (); var bindable = new Bindable ();
Assert.IsNull (bindable.Foo); 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 = { Properties = {
{ new XmlName (null, "Foo"), node }, { new XmlName (null, "Foo"), node },
} }
@ -180,7 +180,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
var bindable = new Bindable (); var bindable = new Bindable ();
Assert.IsNull (bindable.Bar); 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 = { Properties = {
{ new XmlName (null, "Bar"), node }, { new XmlName (null, "Bar"), node },
} }
@ -200,7 +200,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
var bindable = new Bindable (); var bindable = new Bindable ();
Assert.IsNull (Bindable.GetQux (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 = { Properties = {
{ new XmlName ("clr-namespace:Xamarin.Forms.Xaml.UnitTests;assembly=Xamarin.Forms.Xaml.UnitTests", "Bindable.Qux"), node }, { 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 (); var bindable = new Bindable ();
Assert.IsNull (bindable.FooBar); 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 = { Properties = {
{ new XmlName (null, "FooBar"), node }, { new XmlName (null, "FooBar"), node },
} }

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

@ -334,6 +334,7 @@
<Compile Include="McIgnorable.xaml.cs"> <Compile Include="McIgnorable.xaml.cs">
<DependentUpon>McIgnorable.xaml</DependentUpon> <DependentUpon>McIgnorable.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="XamlLoaderCreateTests.cs" />
</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" />

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

@ -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);
}
}
}

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

@ -307,19 +307,25 @@ namespace Xamarin.Forms.Xaml
if (eventInfo != null && value is string) if (eventInfo != null && value is string)
{ {
var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value); var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value);
if (methodInfo == null) if (methodInfo == null) {
{ var xpe = new XamlParseException (string.Format ("No method {0} found on type {1}", value, rootElement.GetType ()), lineInfo);
throw new XamlParseException(string.Format("No method {0} found on type {1}", value, rootElement.GetType()), if (context.DoNotThrowOnExceptions) {
lineInfo); System.Diagnostics.Debug.WriteLine (xpe.Message);
return;
} else
throw xpe;
} }
try try
{ {
eventInfo.AddEventHandler(xamlelement, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement)); eventInfo.AddEventHandler(xamlelement, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement));
} }
catch (ArgumentException) 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; 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) void SetTemplate(ElementTemplate dt, INode node)

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

@ -66,7 +66,7 @@ namespace Xamarin.Forms.Xaml
return; return;
XamlParseException xpe; 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); out xpe);
if (xpe != null) if (xpe != null)
throw xpe; throw xpe;

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

@ -18,5 +18,7 @@ namespace Xamarin.Forms.Xaml
public HydratationContext ParentContext { get; set; } public HydratationContext ParentContext { get; set; }
public BindableObject RootElement { get; set; } public BindableObject RootElement { get; set; }
public bool DoNotThrowOnExceptions { get; set; }
} }
} }

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

@ -62,25 +62,55 @@ namespace Xamarin.Forms.Xaml
continue; continue;
} }
var rootnode = new RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), view); var rootnode = new RuntimeRootNode (new XmlType (reader.NamespaceURI, reader.Name, null), view, (IXmlNamespaceResolver)reader);
XamlParser.ParseXaml (rootnode, reader);
XamlParser.ParseXaml(rootnode, reader); Visit (rootnode, new HydratationContext { RootElement = view });
var visitorContext = new HydratationContext { RootElement = view };
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);
break; break;
} }
} }
} }
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;
}
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) static string GetXamlForType(Type type)
{ {
var assembly = type.GetTypeInfo().Assembly; var assembly = type.GetTypeInfo().Assembly;
@ -197,12 +227,12 @@ namespace Xamarin.Forms.Xaml
public class RuntimeRootNode : RootNode 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; Root = root;
} }
public object Root { get; private set; } public object Root { get; internal set; }
} }
} }
} }

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

@ -178,7 +178,7 @@ namespace Xamarin.Forms.Xaml
internal abstract class RootNode : ElementNode 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)
{ {
} }