[NUI] add support for parameterized constructor in xaml (#1998)
authorYeongJong Lee <cleanlyj@naver.com>
Thu, 10 Sep 2020 05:15:56 +0000 (14:15 +0900)
committerGitHub <noreply@github.com>
Thu, 10 Sep 2020 05:15:56 +0000 (14:15 +0900)
In xaml, root element is now able to be instantiated by parameterized
constructor.

 ### Sample
```cs
namespace NUIXamlTemplate1
{
    public class TestClass
    {
        public TestClass([Parameter(nameof(PropertyForConstructor))] string propertyForConstructor)
        {
            PropertyForConstructor = propertyForConstructor;
        }

        public string PropertyForConstructor { get; }
    }
}

```

```xaml
<local:TestClass
    xmlns="http://tizen.org/Tizen.NUI/2018/XAML"
    xmlns:local="clr-namespace:NUIXamlTemplate1;assembly=NUIXamlTemplate1"
    PropertyForConstructor="test property"
    >

</local:TestClass>
```

```cs
protected override void OnCreate()
{
    base.OnCreate();
    Window.Instance.KeyEvent += OnKeyEvent;

    View root = new View();
    Window.Instance.GetDefaultLayer().Add(root);

    TestClass testClass;
    using (var reader = XmlReader.Create(Tizen.Applications.Application.Current.DirectoryInfo.Resource + "/TestXaml.xaml"))
    {
        testClass = XamlLoader.Create(reader) as TestClass;
    }
    string property = testClass.PropertyForConstructor;   //"test property"
}
```

src/Tizen.NUI/src/internal/Xaml/XamlLoader.cs
src/Tizen.NUI/src/public/Xaml/XamlServiceProvider.cs

index a9aec66..faae3b2 100755 (executable)
@@ -30,6 +30,7 @@ using System.Collections.Generic;
 using System.ComponentModel;
 using System.Diagnostics;
 using System.IO;
+using System.Linq;
 using System.Reflection;
 using System.Text.RegularExpressions;
 using System.Xml;
@@ -208,6 +209,36 @@ namespace Tizen.NUI.Xaml
                         ExceptionHandler = doNotThrow ? e => { } : (Action<Exception>)null,
                     };
                     var cvv = new CreateValuesVisitor(visitorContext);
+
+                    // Visit Parameter Properties to create instance from parameterized constructor
+                    var type = XamlParser.GetElementType(rootnode.XmlType, rootnode, null, out XamlParseException xpe);
+                    if (xpe != null)
+                        throw xpe;
+
+                    var ctorInfo =
+                        type.GetTypeInfo()
+                            .DeclaredConstructors.FirstOrDefault(
+                                ci =>
+                                    ci.GetParameters().Length != 0 && ci.IsPublic &&
+                                    ci.GetParameters().All(pi => pi.CustomAttributes.Any(attr => attr.AttributeType == typeof(ParameterAttribute))));
+                    if (ctorInfo != null)
+                    {
+                        foreach (var parameter in ctorInfo.GetParameters())
+                        {
+                            var propname =
+                                parameter.CustomAttributes.First(ca => ca.AttributeType.FullName == "Tizen.NUI.Binding.ParameterAttribute")?
+                                    .ConstructorArguments.First()
+                                    .Value as string;
+
+                            var name = new XmlName("", propname);
+                            if (rootnode.Properties.TryGetValue(name, out INode node) && node is ValueNode)
+                            {
+                                node.Accept(cvv, rootnode);
+                            }
+                        }
+                    }
+
+
                     cvv.Visit((ElementNode)rootnode, null);
                     inflatedView = rootnode.Root = visitorContext.Values[rootnode];
                     visitorContext.RootElement = inflatedView as BindableObject;
index 0062f5f..aee0c33 100755 (executable)
@@ -24,7 +24,7 @@ namespace Tizen.NUI.Xaml
             if (node != null)
             {
                 IXamlTypeResolver = new XamlTypeResolver(node.NamespaceResolver, XamlParser.GetElementType,
-                    context?.RootElement.GetType().GetTypeInfo().Assembly);
+                    context?.RootElement?.GetType().GetTypeInfo().Assembly);
 
                 Add(typeof(IReferenceProvider), new ReferenceProvider(node));
             }