[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
{
public ILRootNode(XmlType xmlType, TypeReference typeReference) : base(xmlType)
public ILRootNode(XmlType xmlType, TypeReference typeReference) : base(xmlType, null)
{
TypeReference = typeReference;
}

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

@ -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 },
}

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

@ -334,6 +334,7 @@
<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" />

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

@ -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)
{
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)

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

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

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

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

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

@ -62,25 +62,55 @@ namespace Xamarin.Forms.Xaml
continue;
}
var rootnode = new RuntimeRootNode(new XmlType(reader.NamespaceURI, reader.Name, null), view);
XamlParser.ParseXaml(rootnode, reader);
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);
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;
}
}
}
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)
{
var assembly = type.GetTypeInfo().Assembly;
@ -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; }
}
}
}

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

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