[NUI] Adjust directory (#903)
[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
453             if (binding == null)
454                 return false;
455
456             if (bindable != null && property != null) {
457                 bindable.SetBinding(property, binding);
458                 return true;
459             }
460
461             if (property != null)
462                 exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support native bindings", lineInfo);
463
464             return false;
465         }
466
467         static bool TrySetValue(object element, BindableProperty property, bool attached, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, out Exception exception)
468         {
469             exception = null;
470
471             var elementType = element.GetType();
472             var bindable = element as BindableObject;
473
474             if (property == null)
475                 return false;
476
477             if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
478                 ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = property;
479
480             Func<MemberInfo> minforetriever;
481             if (attached)
482                 minforetriever = () => property.DeclaringType.GetRuntimeMethod("Get" + property.PropertyName, new [] { typeof(BindableObject) });
483             else
484             {
485                 minforetriever = () => property.DeclaringType.GetRuntimeProperties().LastOrDefault(p => p.Name == property.PropertyName);
486             }
487             //minforetriever = () => property.DeclaringType.GetRuntimeProperty(property.PropertyName);
488             var convertedValue = value.ConvertTo(property.ReturnType, minforetriever, serviceProvider);
489
490             if (bindable != null) {
491                 //SetValue doesn't throw on mismatching type, so check before to get a chance to try the property setting or the collection adding
492                 var nullable = property.ReturnTypeInfo.IsGenericType &&
493                                property.ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
494                 if ((convertedValue == null && (!property.ReturnTypeInfo.IsValueType || nullable)) ||
495                     (property.ReturnType.IsInstanceOfType(convertedValue))) {
496                     bindable.SetValue(property, convertedValue);
497                     return true;
498                 }
499
500                 // This might be a collection; see if we can add to it
501                 return TryAddValue(bindable, property, value, serviceProvider);
502             }
503
504             exception = new XamlParseException($"{elementType.Name} is not a BindableObject or does not support setting native BindableProperties", lineInfo);
505             return false;
506         }
507
508         static bool TryGetValue(object element, BindableProperty property, bool attached, out object value, IXmlLineInfo lineInfo, out Exception exception, out object targetProperty)
509         {
510             exception = null;
511             value = null;
512             targetProperty = property;
513             var elementType = element.GetType();
514             var bindable = element as BindableObject;
515
516             if (property == null)
517                 return false;
518
519             if (bindable == null)
520                 return false;
521
522             value = bindable.GetValue(property);
523             return true;
524         }
525
526         static bool TrySetProperty(object element, string localName, object value, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
527         {
528             exception = null;
529
530             var elementType = element.GetType();
531             var propertyInfo = elementType.GetRuntimeProperties().FirstOrDefault(p => p.Name == localName);
532             MethodInfo setter;
533             if (propertyInfo == null || !propertyInfo.CanWrite || (setter = propertyInfo.SetMethod) == null)
534                 return false;
535
536             if (!IsVisibleFrom(setter, context.RootElement))
537                 return false;
538
539             if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
540                 ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = propertyInfo;
541
542             object convertedValue = value.ConvertTo(propertyInfo.PropertyType, () => propertyInfo, serviceProvider);
543             if (convertedValue != null && !propertyInfo.PropertyType.IsInstanceOfType(convertedValue))
544                 return false;
545
546             setter.Invoke(element, new object [] { convertedValue });
547             return true;
548         }
549
550         static bool TryGetProperty(object element, string localName, out object value, IXmlLineInfo lineInfo, HydrationContext context, out Exception exception, out object targetProperty)
551         {
552             exception = null;
553             value = null;
554             var elementType = element.GetType();
555             PropertyInfo propertyInfo = null;
556             try {
557                 propertyInfo = elementType.GetRuntimeProperty(localName);
558             } catch (AmbiguousMatchException) {
559                 // Get most derived instance of property
560                 foreach (var property in elementType.GetRuntimeProperties().Where(prop => prop.Name == localName)) {
561                     if (propertyInfo == null || propertyInfo.DeclaringType.IsAssignableFrom(property.DeclaringType))
562                         propertyInfo = property;
563                 }
564             }
565             MethodInfo getter;
566             targetProperty = propertyInfo;
567             if (propertyInfo == null || !propertyInfo.CanRead || (getter = propertyInfo.GetMethod) == null)
568                 return false;
569
570             if (!IsVisibleFrom(getter, context.RootElement))
571                 return false;
572
573             value = getter.Invoke(element, new object[] { });
574             return true;
575         }
576
577         static bool IsVisibleFrom(MethodInfo method, object rootElement)
578         {
579             if (method.IsPublic)
580                 return true;
581             if (method.IsPrivate && method.DeclaringType == rootElement.GetType())
582                 return true;
583             if ((method.IsAssembly || method.IsFamilyOrAssembly) && method.DeclaringType.AssemblyQualifiedName == rootElement.GetType().AssemblyQualifiedName)
584                 return true;
585             if (method.IsFamily && method.DeclaringType.IsAssignableFrom(rootElement.GetType()))
586                 return true;
587             return false;
588         }
589
590         static bool TryAddToProperty(object element, XmlName propertyName, object value, string xKey, IXmlLineInfo lineInfo, XamlServiceProvider serviceProvider, HydrationContext context, out Exception exception)
591         {
592             exception = null;
593
594             object targetProperty;
595             var collection = GetPropertyValue(element, propertyName, context, lineInfo, out targetProperty) as IEnumerable;
596
597             if (collection == null)
598                 return false;
599
600             if (exception == null && TryAddToResourceDictionary(collection as ResourceDictionary, value, xKey, lineInfo, out exception))
601                 return true;
602
603             if (exception != null)
604                 return false;
605
606             var addMethod = collection.GetType().GetRuntimeMethods().First(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
607             if (addMethod == null)
608                 return false;
609
610             if (serviceProvider != null && serviceProvider.IProvideValueTarget != null)
611                 ((XamlValueTargetProvider)serviceProvider.IProvideValueTarget).TargetProperty = targetProperty;
612
613             addMethod.Invoke(collection, new [] { value.ConvertTo(addMethod.GetParameters() [0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
614             return true;
615         }
616
617         static bool TryAddToResourceDictionary(ResourceDictionary resourceDictionary, object value, string xKey, IXmlLineInfo lineInfo, out Exception exception)
618         {
619             exception = null;
620
621             if (resourceDictionary == null)
622                 return false;
623
624             if (xKey != null)
625                 resourceDictionary.Add(xKey, value);
626             else if (value is Tizen.NUI.Binding.Style)
627                 resourceDictionary.Add((Tizen.NUI.Binding.Style)value);
628             else if (value is ResourceDictionary)
629                 resourceDictionary.Add((ResourceDictionary)value);
630             else if (value is StyleSheets.StyleSheet)
631                 resourceDictionary.Add((StyleSheets.StyleSheet)value);
632             else {
633                 exception = new XamlParseException("resources in ResourceDictionary require a x:Key attribute", lineInfo);
634                 return false;
635             }
636             return true;
637         }
638
639         void SetTemplate(ElementTemplate dt, INode node)
640         {
641 #pragma warning disable 0612
642             ((IDataTemplate)dt).LoadTemplate = () => {
643 #pragma warning restore 0612
644                 var cnode = node.Clone();
645                 var context = new HydrationContext { ParentContext = Context, RootElement = Context.RootElement };
646                 cnode.Accept(new XamlNodeVisitor((n, parent) => n.Parent = parent), node.Parent); //set parents for {StaticResource}
647                 cnode.Accept(new ExpandMarkupsVisitor(context), null);
648                 cnode.Accept(new NamescopingVisitor(context), null);
649                 cnode.Accept(new CreateValuesVisitor(context), null);
650                 cnode.Accept(new RegisterXNamesVisitor(context), null);
651                 cnode.Accept(new FillResourceDictionariesVisitor(context), null);
652                 cnode.Accept(new ApplyPropertiesVisitor(context, true), null);
653                 return context.Values [cnode];
654             };
655         }
656
657         static bool TryAddValue(BindableObject bindable, BindableProperty property, object value, XamlServiceProvider serviceProvider)
658         {
659             if(property?.ReturnTypeInfo?.GenericTypeArguments == null){
660                 return false;
661             }
662
663             if(property.ReturnType == null){
664                 return false;
665             }
666
667             if (property.ReturnTypeInfo.GenericTypeArguments.Length != 1 ||
668                 !property.ReturnTypeInfo.GenericTypeArguments[0].IsInstanceOfType(value))
669                 return false;
670
671             // This might be a collection we can add to; see if we can find an Add method
672             var addMethod = GetAllRuntimeMethods(property.ReturnType)
673                 .FirstOrDefault(mi => mi.Name == "Add" && mi.GetParameters().Length == 1);
674             if (addMethod == null)
675                 return false;
676
677             // If there's an add method, get the collection
678             var collection = bindable.GetValue(property);
679             
680             // And add the new value to it
681             addMethod.Invoke(collection, new[] { value.ConvertTo(addMethod.GetParameters()[0].ParameterType, (Func<TypeConverter>)null, serviceProvider) });
682             return true;
683         }
684
685         static IEnumerable<MethodInfo> GetAllRuntimeMethods(Type type)
686         {
687             return type.GetRuntimeMethods()
688                 .Concat(type.GetTypeInfo().ImplementedInterfaces.SelectMany(t => t.GetRuntimeMethods()));
689         }
690
691         bool TrySetRuntimeName(XmlName propertyName, object source, object value, ValueNode node)
692         {
693             if (propertyName != XmlName.xName)
694                 return false;
695
696             var runTimeName = source.GetType().GetTypeInfo().GetCustomAttribute<RuntimeNamePropertyAttribute>();
697             if (runTimeName == null)
698                 return false;
699
700             SetPropertyValue(source, new XmlName("", runTimeName.Name), value, Context.RootElement, node, Context, node);
701             return true;
702         }
703     }
704 }