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