8c5f198e7c5f6afe14b1854d0c51fb07f1d782b1
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.XamlBuild / src / internal / Xaml / ApplyPropertiesVisitor.cs
1 using System;
2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Reflection;
6 using System.Xml;
7 using Tizen.NUI.Binding.Internals;
8 using Tizen.NUI.Binding;
9 using Tizen.NUI.StyleSheets;
10
11 using static System.String;
12
13 namespace Tizen.NUI.Xaml
14 {
15     internal class ApplyPropertiesVisitor : IXamlNodeVisitor
16     {
17         public static readonly IList<XmlName> Skips = new List<XmlName> {
18             XmlName.xKey,
19             XmlName.xTypeArguments,
20             XmlName.xArguments,
21             XmlName.xFactoryMethod,
22             XmlName.xName,
23             XmlName.xDataType
24         };
25
26         public ApplyPropertiesVisitor(HydrationContext context, bool stopOnResourceDictionary = false)
27         {
28             Context = context;
29             StopOnResourceDictionary = stopOnResourceDictionary;
30         }
31
32         Dictionary<INode, object> Values => Context.Values;
33         HydrationContext Context { get; }
34
35         public TreeVisitingMode VisitingMode => TreeVisitingMode.BottomUp;
36         public bool StopOnDataTemplate => true;
37         public bool StopOnResourceDictionary { get; }
38         public bool VisitNodeOnDataTemplate => true;
39         public bool SkipChildren(INode node, INode parentNode) => false;
40         public bool IsResourceDictionary(ElementNode node) => typeof(ResourceDictionary).IsAssignableFrom(Context.Types[node]);
41
42         public void Visit(ValueNode node, INode parentNode)
43         {
44             var parentElement = parentNode as IElementNode;
45             var value = Values [node];
46             var source = Values [parentNode];
47             XmlName propertyName;
48
49             if (TryGetPropertyName(node, parentNode, out propertyName)) {
50                 if (TrySetRuntimeName(propertyName, source, value, node))
51                     return;
52                 if (Skips.Contains(propertyName))
53                     return;
54                 if (parentElement.SkipProperties.Contains(propertyName))
55                     return;
56                 if (propertyName.Equals(XamlParser.McUri, "Ignorable"))
57                     return;
58                 SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
59             } else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
60                 // Collection element, implicit content, or implicit collection element.
61                 var contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo());
62                 if (contentProperty != null) {
63                     var name = new XmlName(((ElementNode)parentNode).NamespaceURI, contentProperty);
64                     if (Skips.Contains(name))
65                         return;
66                     if (parentElement.SkipProperties.Contains(propertyName))
67                         return;
68                     SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
69                 }
70             }
71         }
72
73         public void Visit(MarkupNode node, INode parentNode)
74         {
75         }
76
77         public void Visit(ElementNode node, INode parentNode)
78         {
79             XmlName propertyName;
80             if (TryGetPropertyName(node, parentNode, out propertyName) && propertyName == XmlName._CreateContent) {
81                 var s0 = Values[parentNode];
82                 if (s0 is ElementTemplate) {
83                     SetTemplate(s0 as ElementTemplate, node);
84                     return;
85                 }
86             }
87
88             var parentElement = parentNode as IElementNode;
89             propertyName = XmlName.Empty;
90
91             //Simplify ListNodes with single elements
92             var pList = parentNode as ListNode;
93             if (pList != null && pList.CollectionItems.Count == 1) {
94                 propertyName = pList.XmlName;
95                 parentNode = parentNode.Parent;
96                 parentElement = parentNode as IElementNode;
97             }
98
99             var value = Values[node];
100
101             if (propertyName != XmlName.Empty || TryGetPropertyName(node, parentNode, out propertyName)) {
102                 if (Skips.Contains(propertyName))
103                     return;
104                 if (parentElement == null)
105                     return;
106                 if (parentElement.SkipProperties.Contains(propertyName))
107                     return;
108
109                 var source = Values[parentNode];
110                 ProvideValue(ref value, node, source, propertyName);
111                 SetPropertyValue(source, propertyName, value, Context.RootElement, node, Context, node);
112             }
113             else if (IsCollectionItem(node, parentNode) && parentNode is IElementNode) {
114                 var source = Values[parentNode];
115                 ProvideValue(ref value, node, source, XmlName.Empty);
116                 string contentProperty;
117                 Exception xpe = null;
118                 var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
119
120                 //ResourceDictionary
121                 if (xpe == null && TryAddToResourceDictionary(source as ResourceDictionary, value, xKey, node, out xpe))
122                     return;
123
124                 // Collection element, implicit content, or implicit collection element.
125                 if (xpe == null && typeof(IEnumerable).IsAssignableFrom(Context.Types[parentElement]) && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) {
126                     var addMethod =
127                         Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
128
129                     addMethod.Invoke(source, new[] { value });
130                     return;
131                 }
132                 if (xpe == null && (contentProperty = GetContentPropertyName(Context.Types[parentElement].GetTypeInfo())) != null) {
133                     var name = new XmlName(node.NamespaceURI, contentProperty);
134                     if (Skips.Contains(name))
135                         return;
136                     if (parentElement.SkipProperties.Contains(propertyName))
137                         return;
138
139                     SetPropertyValue(source, name, value, Context.RootElement, node, Context, node);
140                     return;
141                 }
142                 if (xpe == null && Context.Types[parentElement].GetRuntimeMethods().Any(mi => mi.Name == "Add" && mi.GetParameters().Length == 1))
143                 {
144                     //if there are similar parameters in the function, this will exist issue.
145                     var addMethod =    Context.Types[parentElement].GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
146                     if(addMethod != null) addMethod.Invoke(source, new[] { value });
147                     return;
148                 }
149                 xpe = xpe ?? new XamlParseException($"Can not set the content of {((IElementNode)parentNode).XmlType.Name} as it doesn't have a ContentPropertyAttribute", node);
150                 if (Context.ExceptionHandler != null)
151                     Context.ExceptionHandler(xpe);
152                 throw xpe;
153             }
154             else if (IsCollectionItem(node, parentNode) && parentNode is ListNode) {
155                 var source = Values[parentNode.Parent];
156                 ProvideValue(ref value, node, source, XmlName.Empty);
157                 var parentList = (ListNode)parentNode;
158                 if (Skips.Contains(parentList.XmlName))
159                     return;
160                 Exception xpe = null;
161                 var xKey = node.Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)node.Properties[XmlName.xKey]).Value as string : null;
162
163                 object _;
164                 var collection = GetPropertyValue(source, parentList.XmlName, Context, parentList, out _) as IEnumerable;
165                 if (collection == null)
166                     xpe = new XamlParseException($"Property {parentList.XmlName.LocalName} is null or is not IEnumerable", node);
167
168                 if (xpe == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, node, out xpe))
169                     return;
170
171                 MethodInfo addMethod;
172                 if (xpe == null && (addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1)) != null) {
173                     addMethod.Invoke(collection, new[] { Values[node] });
174                     return;
175                 }
176                 xpe = xpe ?? new XamlParseException($"Value of {parentList.XmlName.LocalName} does not have a Add() method", node);
177                 if (Context.ExceptionHandler != null)
178                     Context.ExceptionHandler(xpe);
179                 else
180                     throw xpe;
181             }
182         }
183
184         
185
186         public void Visit(RootNode node, INode parentNode)
187         {
188         }
189
190         public void Visit(ListNode node, INode parentNode)
191         {
192         }
193
194         public static bool TryGetPropertyName(INode node, INode parentNode, out XmlName name)
195         {
196             name = default(XmlName);
197             var parentElement = parentNode as IElementNode;
198             if (parentElement == null)
199                 return false;
200             foreach (var kvp in parentElement.Properties) {
201                 if (kvp.Value != node)
202                     continue;
203                 name = kvp.Key;
204                 return true;
205             }
206             return false;
207         }
208
209         internal static bool IsCollectionItem(INode node, INode parentNode)
210         {
211             var parentList = parentNode as IListNode;
212             if (parentList == null)
213                 return false;
214             return parentList.CollectionItems.Contains(node);
215         }
216
217         internal static string GetContentPropertyName(System.Reflection.TypeInfo typeInfo)
218         {
219             while (typeInfo != null) {
220                 var propName = GetContentPropertyName(typeInfo.CustomAttributes);
221                 if (propName != null)
222                     return propName;
223                 typeInfo = typeInfo?.BaseType?.GetTypeInfo();
224             }
225             return null;
226         }
227
228         void ProvideValue(ref object value, ElementNode node, object source, XmlName propertyName)
229         {
230             var markupExtension = value as IMarkupExtension;
231             var valueProvider = value as IValueProvider;
232
233             if (markupExtension == null && valueProvider == null)
234                 return;
235
236             XamlServiceProvider serviceProvider = null;
237             if (value.GetType().GetTypeInfo().GetCustomAttribute<AcceptEmptyServiceProviderAttribute>() == null)
238                 serviceProvider = new XamlServiceProvider(node, Context);
239
240             if (serviceProvider != null && serviceProvider.IProvideValueTarget != null && propertyName != XmlName.Empty)
241                 ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = GetTargetProperty(source, propertyName, Context, node);
242
243             if (markupExtension != null)
244                 value = markupExtension.ProvideValue(serviceProvider);
245             else if (valueProvider != null)
246                 value = valueProvider.ProvideValue(serviceProvider);
247         }
248
249         static string GetContentPropertyName(IEnumerable<CustomAttributeData> attributes)
250         {
251             var contentAttribute =
252                 attributes.FirstOrDefault(cad => ContentPropertyAttribute.ContentPropertyTypes.Contains(cad.AttributeType.FullName));
253             if (contentAttribute == null || contentAttribute.ConstructorArguments.Count != 1)
254                 return null;
255             if (contentAttribute.ConstructorArguments [0].ArgumentType == typeof(string))
256                 return (string)contentAttribute.ConstructorArguments [0].Value;
257             return null;
258         }
259
260         static bool GetRealNameAndType(ref Type elementType, string namespaceURI, ref string localname,
261             HydrationContext context, IXmlLineInfo lineInfo)
262         {
263             var dotIdx = localname.IndexOf('.');
264             if (dotIdx > 0) {
265                 var typename = localname.Substring(0, dotIdx);
266                 localname = localname.Substring(dotIdx + 1);
267                 XamlParseException xpe;
268                 elementType = XamlParser.GetElementType(new XmlType(namespaceURI, typename, null), lineInfo,
269                     context.RootElement.GetType().GetTypeInfo().Assembly, out xpe);
270
271                 if (xpe != null)
272                     throw xpe;
273                 return true;
274             }
275             return false;
276         }
277
278         static BindableProperty GetBindableProperty(Type elementType, string localName, IXmlLineInfo lineInfo,
279             bool throwOnError = false)
280         {
281 #if NETSTANDARD1_0
282             var bindableFieldInfo = elementType.GetFields().FirstOrDefault(fi => fi.Name == localName + "Property");
283 #else
284             var bindableFieldInfo = elementType.GetFields(BindingFlags.Static | BindingFlags.NonPublic|BindingFlags.FlattenHierarchy).FirstOrDefault(fi => fi.Name == localName + "Property");
285
286             if (null == bindableFieldInfo)
287             {
288                 bindableFieldInfo = elementType.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy).FirstOrDefault(fi => fi.Name == localName + "Property");
289             }
290 #endif
291             Exception exception = null;
292             if (exception == null && bindableFieldInfo == null) {
293                 exception =
294                     new XamlParseException(
295                         Format("BindableProperty {0} not found on {1}", localName + "Property", elementType.Name), lineInfo);
296             }
297
298             if (exception == null)
299                 return bindableFieldInfo.GetValue(null) as BindableProperty;
300             if (throwOnError)
301                 throw exception;
302             return null;
303         }
304
305         static object GetTargetProperty(object xamlelement, XmlName propertyName, HydrationContext context, IXmlLineInfo lineInfo)
306         {
307             var localName = propertyName.LocalName;
308             //If it's an attached BP, update elementType and propertyName
309             var bpOwnerType = xamlelement.GetType();
310             GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo);
311             var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false);
312
313             if (property != null)
314                 return property;
315             
316             var elementType = xamlelement.GetType();
317             var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName);
318             return propertyInfo;
319         }
320
321         public static void SetPropertyValue(object xamlelement, XmlName propertyName, object value, object rootElement, INode node, HydrationContext context, IXmlLineInfo lineInfo)
322         {
323             var localName = propertyName.LocalName;
324             var serviceProvider = new XamlServiceProvider(node, context);
325             Exception xpe = null;
326             var xKey = node is IElementNode && ((IElementNode)node).Properties.ContainsKey(XmlName.xKey) ? ((ValueNode)((IElementNode)node).Properties[XmlName.xKey]).Value as string : null;
327
328             //If it's an attached BP, update elementType and propertyName
329             var bpOwnerType = xamlelement.GetType();
330             var attached = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo);
331             var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false);
332
333             //If the target is an event, connect
334             if (xpe == null && TryConnectEvent(xamlelement, localName, attached, value, rootElement, lineInfo, out xpe))
335                 return;
336
337             //If Value is DynamicResource and it's a BP, SetDynamicResource
338             if (xpe == null && TrySetDynamicResource(xamlelement, property, value, lineInfo, out xpe))
339                 return;
340
341             //If value is BindingBase, SetBinding
342             if (xpe == null && TrySetBinding(xamlelement, property, localName, value, lineInfo, out xpe))
343                 return;
344
345             //If it's a BindableProberty, SetValue
346             if (xpe == null && TrySetValue(xamlelement, property, attached, value, lineInfo, serviceProvider, out xpe))
347                 return;
348
349             //If we can assign that value to a normal property, let's do it
350             if (xpe == null && TrySetProperty(xamlelement, localName, value, lineInfo, serviceProvider, context, out xpe))
351                 return;
352
353             //If it's an already initialized property, add to it
354             if (xpe == null && TryAddToProperty(xamlelement, propertyName, value, xKey, lineInfo, serviceProvider, context, out xpe))
355                 return;
356
357             xpe = xpe ?? new XamlParseException($"Cannot assign property \"{localName}\": Property does not exist, or is not assignable, or mismatching type between value and property", lineInfo);
358             if (context.ExceptionHandler != null)
359                 context.ExceptionHandler(xpe);
360             else
361                 throw xpe;
362         }
363
364         public static object GetPropertyValue(object xamlElement, XmlName propertyName, HydrationContext context, IXmlLineInfo lineInfo, out object targetProperty)
365         {
366             var localName = propertyName.LocalName;
367             Exception xpe = null;
368             object value;
369             targetProperty = null;
370
371             //If it's an attached BP, update elementType and propertyName
372             var bpOwnerType = xamlElement.GetType();
373             var attached = GetRealNameAndType(ref bpOwnerType, propertyName.NamespaceURI, ref localName, context, lineInfo);
374             var property = GetBindableProperty(bpOwnerType, localName, lineInfo, false);
375
376             //If it's a BindableProberty, GetValue
377             if (xpe == null && TryGetValue(xamlElement, property, attached, out value, lineInfo, out xpe, out targetProperty))
378                 return value;
379
380             //If it's a normal property, get it
381             if (xpe == null && TryGetProperty(xamlElement, localName, out value, lineInfo, context, out xpe, out targetProperty))
382                 return value;
383
384             xpe = xpe ?? new XamlParseException($"Property {localName} is not found or does not have an accessible getter", lineInfo);
385             if (context.ExceptionHandler != null)
386                 context.ExceptionHandler(xpe);
387             else
388                 throw xpe;
389
390             return null;
391         }
392
393         static bool TryConnectEvent(object element, string localName, bool attached, object value, object rootElement, IXmlLineInfo lineInfo, out Exception exception)
394         {
395             exception = null;
396
397             if (attached)
398                 return false;
399
400             var elementType = element.GetType();
401             var eventInfo = elementType.GetRuntimeEvent(localName);
402             var stringValue = value as string;
403
404             if (eventInfo == null || IsNullOrEmpty(stringValue))
405                 return false;
406
407             var methodInfo = rootElement.GetType().GetRuntimeMethods().FirstOrDefault(mi => mi.Name == (string)value);
408             if (methodInfo == null) {
409                 exception = new XamlParseException($"No method {value} found on type {rootElement.GetType()}", lineInfo);
410                 return false;
411             }
412
413             try {
414                 eventInfo.AddEventHandler(element, methodInfo.CreateDelegate(eventInfo.EventHandlerType, rootElement));
415                 return true;
416             } catch (ArgumentException ae) {
417                 exception = new XamlParseException($"Method {stringValue} does not have the correct signature", lineInfo, ae);
418             }
419             return false;
420         }
421
422         static bool TrySetDynamicResource(object element, BindableProperty property, object value, IXmlLineInfo lineInfo, out Exception exception)
423         {
424             exception = null;
425
426             var elementType = element.GetType();
427             var dynamicResource = value as DynamicResource;
428             var bindable = element as BindableObject;
429
430             if (dynamicResource == null || property == null)
431                 return false;
432
433             if (bindable == null) {
434                 exception = new XamlParseException($"{elementType.Name} is not a BindableObject", lineInfo);
435                 return false;
436             }
437
438             bindable.SetDynamicResource(property, dynamicResource.Key);
439             return true;
440         }
441
442         static bool TrySetBinding(object element, BindableProperty property, string localName, object value, IXmlLineInfo lineInfo, out Exception exception)
443         {
444             exception = null;
445
446             var elementType = element.GetType();
447             var binding = value.ConvertTo(typeof(BindingBase),pinfoRetriever:null,serviceProvider:null) as BindingBase;
448             var bindable = element as BindableObject;
449             var nativeBindingService = DependencyService.Get<INativeBindingService>();
450
451             if (binding == null)
452                 return false;
453
454             if (bindable != null && property != null) {
455                 bindable.SetBinding(property, binding);
456                 return true;
457             }
458
459             if (nativeBindingService != null && property != null && nativeBindingService.TrySetBinding(element, property, binding))
460                 return true;
461
462             if (nativeBindingService != null && nativeBindingService.TrySetBinding(element, localName, binding))
463                 return true;
464
465             if (property != null)
466                 exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support native bindings", lineInfo);
467
468             return false;
469         }
470
471         static bool TrySetValue(object element, BindableProperty property, bool attached, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, out Exception exception)
472         {
473             exception = null;
474
475             var elementType = element.GetType();
476             var bindable = element as BindableObject;
477             var nativeBindingService = DependencyService.Get<INativeBindingService>();
478
479             if (property == null)
480                 return false;
481
482             if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
483                 ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = property;
484
485             Func<MemberInfo> minforetriever;
486             if (attached)
487                 minforetriever = () => property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new [] { typeof(BindableObject) });
488             else
489             {
490                 minforetriever = () => property.DeclaringType.GetRuntimeProperties().LastOrDefault(p => p.Name == property.PropertyName);
491             }
492             //minforetriever = () => property.DeclaringType.GetRuntimeProperty(property.PropertyName);
493             var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);
494
495             if (bindable != null) {
496                 //SetValue doesn't throw on mismatching type, so check before to get a chance to try the property setting or the collection adding
497                 var nullable = property.ReturnTypeInfo.IsGenericType &&
498                                property.ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
499                 if ((convertedValue == null && (!property.ReturnTypeInfo.IsValueType || nullable)) ||
500                     (property.ReturnType.IsInstanceOfType(convertedValue))) {
501                     bindable.SetValue(property, convertedValue);
502                     return true;
503                 }
504
505                 // This might be a collection; see if we can add to it
506                 return TryAddValue(bindable, property, value, serviceProvider);
507             }
508
509             if (nativeBindingService != null && nativeBindingService.TrySetValue(element, property, convertedValue))
510                 return true;
511
512             exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support setting native BindableProperties", lineInfo);
513             return false;
514         }
515
516         static bool TryGetValue(object element, BindableProperty property, bool attached, out object value, IXmlLineInfo lineInfo, out Exception exception, out object targetProperty)
517         {
518             exception = null;
519             value = null;
520             targetProperty = property;
521             var elementType = element.GetType();
522             var bindable = element as BindableObject;
523
524             if (property == null)
525                 return false;
526
527             if (bindable == null)
528                 return false;
529
530             value = bindable.GetValue(property);
531             return true;
532         }
533
534         static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
535         {
536             exception = null;
537
538             var elementType = element.GetType();
539             var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName);
540             MethodInfo setter;
541             if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null)
542                 return false;
543
544             if (!IsVisibleFrom(setter, context.RootElement))
545                 return false;
546
547             if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
548                 ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = propertyInfo;
549
550             object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider);
551             if (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue))
552                 return false;
553
554             setter.Invoke(element, new object [] { convertedValue });
555             return true;
556         }
557
558         static bool TryGetProperty(object element, string localName, out object value, IXmlLineInfo lineInfo, HydrationContext context, out Exception exception, out object targetProperty)
559         {
560             exception = null;
561             value = null;
562             var elementType = element.GetType();
563             PropertyInfo propertyInfo = null;
564             try {
565                 propertyInfo = elementType.GetRuntimeProperty(localName);
566             } catch (AmbiguousMatchException) {
567                 // Get most derived instance of property
568                 foreach (var property in elementType.GetRuntimeProperties().Where(prop => prop.Name == localName)) {
569                     if (propertyInfo == null || propertyInfo.DeclaringType.IsAssignableFrom(property.DeclaringType))
570                         propertyInfo = property;
571                 }
572             }
573             MethodInfo getter;
574             targetProperty = propertyInfo;
575             if (propertyInfo == null || !propertyInfo.CanRead || (getter = propertyInfo.GetMethod) == null)
576                 return false;
577
578             if (!IsVisibleFrom(getter, context.RootElement))
579                 return false;
580
581             value = getter.Invoke(element, new object[] { });
582             return true;
583         }
584
585         static bool IsVisibleFrom(MethodInfo method, object rootElement)
586         {
587             if (method.IsPublic)
588                 return true;
589             if (method.IsPrivate && method.DeclaringType == rootElement.GetType())
590                 return true;
591             if ((method.IsAssembly || method.IsFamilyOrAssembly) && method.DeclaringType.AssemblyQualifiedName == rootElement.GetType().AssemblyQualifiedName)
592                 return true;
593             if (method.IsFamily && method.DeclaringType.IsAssignableFrom(rootElement.GetType()))
594                 return true;
595             return false;
596         }
597
598         static bool TryAddToProperty(object element, XmlName propertyName, object value, string xKey, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
599         {
600             exception = null;
601
602             object targetProperty;
603             var collection = GetPropertyValue(element, propertyName, context, lineInfo, out targetProperty) as IEnumerable;
604
605             if (collection == null)
606                 return false;
607
608             if (exception == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, lineInfo, out exception))
609                 return true;
610
611             if (exception != null)
612                 return false;
613
614             var addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
615             if (addMethod == null)
616                 return false;
617
618             if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
619                 ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty;
620
621             addMethod.Invoke(collection, new [] { value.ConvertTo(addMethod.GetParameters() [0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
622             return true;
623         }
624
625         static bool TryAddToResourceDictionary(ResourceDictionary resourceDictionary, object value, string xKey, IXmlLineInfo lineInfo, out Exception exception)
626         {
627             exception = null;
628
629             if (resourceDictionary == null)
630                 return false;
631
632             if (xKey != null)
633                 resourceDictionary.Add(xKey, value);
634             else if (value is Tizen.NUI.Binding.Style)
635                 resourceDictionary.Add((Tizen.NUI.Binding.Style)value);
636             else if (value is ResourceDictionary)
637                 resourceDictionary.Add((ResourceDictionary)value);
638             else if (value is StyleSheets.StyleSheet)
639                 resourceDictionary.Add((StyleSheets.StyleSheet)value);
640             else {
641                 exception = new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
642                 return false;
643             }
644             return true;
645         }
646
647         void SetTemplate(ElementTemplate dt, INode node)
648         {
649 #pragma warning disable 0612
650             ((IDataTemplate)dt).LoadTemplate = () => {
651 #pragma warning restore 0612
652                 var cnode = node.Clone();
653                 var context = new HydrationContext { ParentContext = Context, RootElement = Context.RootElement };
654                 cnode.Accept(new XamlNodeVisitor((n, parent) => n.Parent = parent), node.Parent); //set parents for {StaticResource}
655                 cnode.Accept(new ExpandMarkupsVisitor(context), null);
656                 cnode.Accept(new NamescopingVisitor(context), null);
657                 cnode.Accept(new CreateValuesVisitor(context), null);
658                 cnode.Accept(new RegisterXNamesVisitor(context), null);
659                 cnode.Accept(new FillResourceDictionariesVisitor(context), null);
660                 cnode.Accept(new ApplyPropertiesVisitor(context, true), null);
661                 return context.Values [cnode];
662             };
663         }
664
665         static bool TryAddValue(BindableObject bindable, BindableProperty property, object value, XamlServiceProvider serviceProvider)
666         {
667             if(property?.ReturnTypeInfo?.GenericTypeArguments == null){
668                 return false;
669             }
670
671             if(property.ReturnType == null){
672                 return false;
673             }
674
675             if (property.ReturnTypeInfo.GenericTypeArguments.Length != 1 ||
676                 !property.ReturnTypeInfo.GenericTypeArguments[0].IsInstanceOfType(value))
677                 return false;
678
679             // This might be a collection we can add to; see if we can find an Add method
680             var addMethod = GetAllRuntimeMethods(property.ReturnType)
681                 .FirstOrDefault(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
682             if (addMethod == null)
683                 return false;
684
685             // If there's an add method, get the collection
686             var collection = bindable.GetValue(property);
687             
688             // And add the new value to it
689             addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
690             return true;
691         }
692
693         static IEnumerable<MethodInfo> GetAllRuntimeMethods(Type type)
694         {
695             return type.GetRuntimeMethods()
696                 .Concat(type.GetTypeInfo().ImplementedInterfaces.SelectMany(t => t.GetRuntimeMethods()));
697         }
698
699         bool TrySetRuntimeName(XmlName propertyName, object source, object value, ValueNode node)
700         {
701             if (propertyName != XmlName.xName)
702                 return false;
703
704             var runTimeName = source.GetType().GetTypeInfo().GetCustomAttribute<RuntimeNamePropertyAttribute>();
705             if (runTimeName == null)
706                 return false;
707
708             SetPropertyValue(source, new XmlName("", runTimeName.Name), value, Context.RootElement, node, Context, node);
709             return true;
710         }
711     }
712 }