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