Revert "[NUI] Roll back to fix build error of TCT code"
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / XamlBinding / BindableProperty.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.Diagnostics;
21 using System.Linq.Expressions;
22 using System.Reflection;
23 using System.ComponentModel;
24 using Tizen.NUI.Binding.Internals;
25 using Tizen.NUI.Xaml;
26
27 namespace Tizen.NUI.Binding
28 {
29     /// <summary>
30     /// A BindableProperty is a backing store for properties allowing bindings on BindableObject.
31     /// </summary>
32     [DebuggerDisplay("{PropertyName}")]
33     [TypeConverter(typeof(BindablePropertyConverter))]
34     [EditorBrowsable(EditorBrowsableState.Never)]
35     public sealed class BindableProperty
36     {
37         /// <summary>
38         /// Delegate for BindableProperty.PropertyChanged.
39         /// </summary>
40         /// <param name="bindable">The bindable object that contains the property.</param>
41         /// <param name="oldValue">The old property value.</param>
42         /// <param name="newValue">The new property value.</param>
43         public delegate void BindingPropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue);
44
45         /// <summary>
46         /// Strongly-typed delegate for BindableProperty.PropertyChanged.
47         /// </summary>
48         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
49         /// <param name="bindable">The bindable object that contains the property.</param>
50         /// <param name="oldValue">The old property value.</param>
51         /// <param name="newValue">The new property value.</param>
52         public delegate void BindingPropertyChangedDelegate<in TPropertyType>(BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
53
54         /// <summary>
55         /// Delegate for BindableProperty.PropertyChanging.
56         /// </summary>
57         /// <param name="bindable">The bindable object that contains the property.</param>
58         /// <param name="oldValue">The old property value.</param>
59         /// <param name="newValue">The new property value.</param>
60         public delegate void BindingPropertyChangingDelegate(BindableObject bindable, object oldValue, object newValue);
61
62         /// <summary>
63         /// Strongly-typed delegate for BindableProperty.PropertyChanging.
64         /// </summary>
65         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
66         /// <param name="bindable">The bindable object that contains the property.</param>
67         /// <param name="oldValue">The old property value.</param>
68         /// <param name="newValue">The new property value.</param>
69         public delegate void BindingPropertyChangingDelegate<in TPropertyType>(BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
70
71         /// <summary>
72         /// Delegate for BindableProperty.CoerceValue.
73         /// </summary>
74         /// <param name="bindable">The bindable object that contains the property.</param>
75         /// <param name="value">The value to coerce.</param>
76         /// <returns>System.Object</returns>
77         public delegate object CoerceValueDelegate(BindableObject bindable, object value);
78
79         /// <summary>
80         /// Strongly-typed delegate for BindableProperty.CoerceValue.
81         /// </summary>
82         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
83         /// <param name="bindable">The bindable object that contains the property.</param>
84         /// <param name="value">The value to coerce.</param>
85         /// <returns>TPropertyType</returns>
86         public delegate TPropertyType CoerceValueDelegate<TPropertyType>(BindableObject bindable, TPropertyType value);
87
88         /// <summary>
89         /// Delegate for BindableProperty.DefaultValueCreator.
90         /// </summary>
91         /// <param name="bindable">The bindable object that contains the property.</param>
92         /// <returns>System.Object</returns>
93         public delegate object CreateDefaultValueDelegate(BindableObject bindable);
94
95         /// <summary>
96         /// Strongly-typed delegate for BindableProperty.DefaultValueCreator.
97         /// </summary>
98         /// <typeparam name="TDeclarer">The type of the object that delared the property.</typeparam>
99         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
100         /// <param name="bindable">The bindable object that contains the property.</param>
101         /// <returns>TPropertyType</returns>
102         public delegate TPropertyType CreateDefaultValueDelegate<in TDeclarer, out TPropertyType>(TDeclarer bindable);
103
104         /// <summary>
105         /// Delegate for BindableProperty.ValidateValue.
106         /// </summary>
107         /// <param name="bindable">The bindable object that contains the property.</param>
108         /// <param name="value">The default value.</param>
109         /// <returns>System.Boolean</returns>
110         public delegate bool ValidateValueDelegate(BindableObject bindable, object value);
111
112         /// <summary>
113         /// Strongly-typed delegate for BindableProperty.ValidateValue.
114         /// </summary>
115         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
116         /// <param name="bindable">The bindable object that contains the property.</param>
117         /// <param name="value">The default value.</param>
118         /// <returns>System.Boolean</returns>
119         public delegate bool ValidateValueDelegate<in TPropertyType>(BindableObject bindable, TPropertyType value);
120
121         //To confirm the static dictionary will be created before the constructor is called.
122         static BindableProperty()
123         {
124         }
125
126         static readonly Dictionary<Type, TypeConverter> WellKnownConvertTypes = new Dictionary<Type, TypeConverter>
127         {
128             { typeof(Uri), new UriTypeConverter() },
129             { typeof(Color), new ColorTypeConverter() },
130             { typeof(Size2D), new Size2DTypeConverter() },
131             { typeof(Position2D), new Position2DTypeConverter() },
132             { typeof(Size), new SizeTypeConverter() },
133             { typeof(Position), new PositionTypeConverter() },
134             { typeof(Rectangle), new RectangleTypeConverter() },
135             { typeof(Rotation), new RotationTypeConverter() },
136             { typeof(Vector2), new Vector2TypeConverter() },
137             { typeof(Vector3), new Vector3TypeConverter() },
138             { typeof(Vector4), new Vector4TypeConverter() },
139             { typeof(RelativeVector2), new RelativeVector2TypeConverter() },
140             { typeof(RelativeVector3), new RelativeVector3TypeConverter() },
141             { typeof(RelativeVector4), new RelativeVector4TypeConverter() },
142         };
143
144         //Modification for NUI XAML : user defined converter for DynamicResource can be added
145         static internal Dictionary<Type, TypeConverter> UserCustomConvertTypes = new Dictionary<Type, TypeConverter>
146         {
147         };
148
149         // more or less the encoding of this, without the need to reflect
150         // http://msdn.microsoft.com/en-us/library/y5b434w4.aspx
151         static readonly Dictionary<Type, Type[]> SimpleConvertTypes = new Dictionary<Type, Type[]>
152         {
153             { typeof(sbyte), new[] { typeof(string), typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
154             { typeof(byte), new[] { typeof(string), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
155             { typeof(short), new[] { typeof(string), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
156             { typeof(ushort), new[] { typeof(string), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
157             { typeof(int), new[] { typeof(string), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
158             { typeof(uint), new[] { typeof(string), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
159             { typeof(long), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } },
160             { typeof(char), new[] { typeof(string), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
161             { typeof(float), new[] { typeof(string), typeof(double) } },
162             { typeof(ulong), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } }
163         };
164
165         BindableProperty(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
166                                  ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
167                                  CoerceValueDelegate coerceValue = null, BindablePropertyBindingChanging bindingChanging = null, bool isReadOnly = false, CreateDefaultValueDelegate defaultValueCreator = null)
168         {
169             if (propertyName == null)
170                 throw new ArgumentNullException(nameof(propertyName));
171             if (ReferenceEquals(returnType, null))
172                 throw new ArgumentNullException(nameof(returnType));
173             if (ReferenceEquals(declaringType, null))
174                 throw new ArgumentNullException(nameof(declaringType));
175
176             // don't use Enum.IsDefined as its redonkulously expensive for what it does
177             if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay && defaultBindingMode != BindingMode.OneTime)
178                 throw new ArgumentException("Not a valid type of BindingMode", nameof(defaultBindingMode));
179             if (defaultValue == null && Nullable.GetUnderlyingType(returnType) == null && returnType.GetTypeInfo().IsValueType)
180                 throw new ArgumentException("Not a valid default value", nameof(defaultValue));
181             if (defaultValue != null && !returnType.IsInstanceOfType(defaultValue))
182                 throw new ArgumentException("Default value did not match return type", nameof(defaultValue));
183             if (defaultBindingMode == BindingMode.Default)
184                 defaultBindingMode = BindingMode.OneWay;
185
186             PropertyName = propertyName;
187             ReturnType = returnType;
188             ReturnTypeInfo = returnType.GetTypeInfo();
189             DeclaringType = declaringType;
190             DefaultValue = defaultValue;
191             DefaultBindingMode = defaultBindingMode;
192             PropertyChanged = propertyChanged;
193             PropertyChanging = propertyChanging;
194             ValidateValue = validateValue;
195             CoerceValue = coerceValue;
196             BindingChanging = bindingChanging;
197             IsReadOnly = isReadOnly;
198             DefaultValueCreator = defaultValueCreator;
199
200             Dictionary<string, BindableProperty> nameToBindableProperty;
201             bindablePropertyOfType.TryGetValue(declaringType, out nameToBindableProperty);
202             if (null == nameToBindableProperty)
203             {
204                 nameToBindableProperty = new Dictionary<string, BindableProperty>();
205                 bindablePropertyOfType.Add(declaringType, nameToBindableProperty);
206             }
207
208             if (!nameToBindableProperty.ContainsKey(propertyName))
209             {
210                 nameToBindableProperty.Add(propertyName, this);
211             }
212             else
213             {
214                 nameToBindableProperty[propertyName] = this;
215             }
216         }
217
218         private static bool AddParentTypeProperty(Type type, Dictionary<string, BindableProperty> propertyDict)
219         {
220             bool ret = false;
221
222             if (null != type)
223             {
224                 Dictionary<string, BindableProperty> nameToBindableProperty;
225                 bindablePropertyOfType.TryGetValue(type, out nameToBindableProperty);
226
227                 if (null != nameToBindableProperty)
228                 {
229                     ret = true;
230
231                     foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty)
232                     {
233                         if (!propertyDict.ContainsKey(keyValuePair.Key))
234                         {
235                             propertyDict.Add(keyValuePair.Key, keyValuePair.Value);
236                         }
237                     }
238                 }
239
240                 if (true == AddParentTypeProperty(type.BaseType, propertyDict))
241                 {
242                     ret = true;
243                 }
244             }
245
246             return ret;
247         }
248
249         static internal Dictionary<Type, Dictionary<string, BindableProperty>> bindablePropertyOfType = new Dictionary<Type, Dictionary<string, BindableProperty>>();
250         static private HashSet<Type> baseTypePropertyHasBeenAdded = new HashSet<Type>();
251
252         static internal void GetBindablePropertysOfType(Type type, out Dictionary<string, BindableProperty> dictionary)
253         {
254             dictionary = null;
255
256             bindablePropertyOfType.TryGetValue(type, out dictionary);
257
258             if (!baseTypePropertyHasBeenAdded.Contains(type))
259             {
260                 bool isCurDictNull = false;
261
262                 if (null == dictionary)
263                 {
264                     isCurDictNull = true;
265                     dictionary = new Dictionary<string, BindableProperty>();
266                 }
267
268                 if (true == AddParentTypeProperty(type.BaseType, dictionary) && true == isCurDictNull)
269                 {
270                     bindablePropertyOfType.Add(type, dictionary);
271                 }
272
273                 baseTypePropertyHasBeenAdded.Add(type);
274             }
275         }
276
277         /// <summary>
278         /// Gets the type declaring the BindableProperty.
279         /// </summary>
280         public Type DeclaringType { get; private set; }
281
282         /// <summary>
283         /// Gets the default BindingMode.
284         /// </summary>
285         public BindingMode DefaultBindingMode { get; private set; }
286
287         /// <summary>
288         /// Gets the default value for the BindableProperty.
289         /// </summary>
290         public object DefaultValue { get; }
291
292         /// <summary>
293         /// Gets a value indicating if the BindableProperty is created form a BindablePropertyKey.
294         /// </summary>
295         public bool IsReadOnly { get; private set; }
296
297         /// <summary>
298         /// Gets the property name.
299         /// </summary>
300         public string PropertyName { get; }
301
302         /// <summary>
303         /// Gets the type of the BindableProperty.
304         /// </summary>
305         public Type ReturnType { get; }
306
307         internal BindablePropertyBindingChanging BindingChanging { get; private set; }
308
309         internal CoerceValueDelegate CoerceValue { get; private set; }
310
311         internal CreateDefaultValueDelegate DefaultValueCreator { get; }
312
313         internal BindingPropertyChangedDelegate PropertyChanged { get; private set; }
314
315         internal BindingPropertyChangingDelegate PropertyChanging { get; private set; }
316
317         internal System.Reflection.TypeInfo ReturnTypeInfo { get; }
318
319         internal ValidateValueDelegate ValidateValue { get; private set; }
320
321         /// <summary>
322         /// Creates a new instance of the BindableProperty class.
323         /// </summary>
324         /// <param name="propertyName">The name of the BindableProperty.</param>
325         /// <param name="returnType">The type of the property.</param>
326         /// <param name="declaringType">The type of the declaring object.</param>
327         /// <param name="defaultValue">The default value for the property.</param>
328         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
329         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
330         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
331         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
332         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
333         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
334         /// <returns>A newly created BindableProperty.</returns>
335         public static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue = null, BindingMode defaultBindingMode = BindingMode.OneWay,
336                                               ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
337                                               CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
338         {
339             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
340                 defaultValueCreator: defaultValueCreator);
341         }
342
343         /// <summary>
344         /// Creates a new instance of the BindableProperty class for an attached property.
345         /// </summary>
346         /// <param name="propertyName">The name of the BindableProperty.</param>
347         /// <param name="returnType">The type of the property.</param>
348         /// <param name="declaringType">The type of the declaring object.</param>
349         /// <param name="defaultValue">The default value for the property.</param>
350         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
351         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
352         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
353         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
354         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
355         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
356         /// <returns>A newly created BindableProperty.</returns>
357         public static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
358                                                       ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
359                                                       CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
360         {
361             return CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false, defaultValueCreator);
362         }
363
364         /// <summary>
365         /// Creates a new instance of the BindableProperty class for attached read-only properties.
366         /// </summary>
367         /// <param name="propertyName">The name of the BindableProperty.</param>
368         /// <param name="returnType">The type of the property.</param>
369         /// <param name="declaringType">The type of the declaring object.</param>
370         /// <param name="defaultValue">The default value for the property.</param>
371         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
372         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
373         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
374         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
375         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
376         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
377         /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
378         public static BindablePropertyKey CreateAttachedReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
379                                                                  ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
380                                                                  CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
381         {
382             return
383                 new BindablePropertyKey(CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
384                     defaultValueCreator));
385         }
386
387         /// <summary>
388         /// Creates a new instance of the BindablePropertyKey class.
389         /// </summary>
390         /// <param name="propertyName">The name of the BindableProperty.</param>
391         /// <param name="returnType">The type of the property.</param>
392         /// <param name="declaringType">The type of the declaring object.</param>
393         /// <param name="defaultValue">The default value for the property.</param>
394         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
395         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
396         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
397         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
398         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
399         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
400         /// <returns>A newly created BindablePropertyKey.</returns>
401         public static BindablePropertyKey CreateReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
402                                                          ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
403                                                          CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
404         {
405             return
406                 new BindablePropertyKey(new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
407                     isReadOnly: true, defaultValueCreator: defaultValueCreator));
408         }
409         internal static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
410                                                 BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
411                                                 CreateDefaultValueDelegate defaultValueCreator = null)
412         {
413             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging,
414                 defaultValueCreator: defaultValueCreator);
415         }
416
417         internal static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
418                                                         BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
419                                                         bool isReadOnly, CreateDefaultValueDelegate defaultValueCreator = null)
420         {
421             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, isReadOnly,
422                 defaultValueCreator);
423         }
424
425         internal object GetDefaultValue(BindableObject bindable)
426         {
427             if (DefaultValueCreator != null)
428                 return DefaultValueCreator(bindable);
429
430             return DefaultValue;
431         }
432
433         internal bool TryConvert(ref object value)
434         {
435             if (value == null)
436             {
437                 return !ReturnTypeInfo.IsValueType || ReturnTypeInfo.IsGenericType && ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
438             }
439
440             Type valueType = value.GetType();
441             Type type = ReturnType;
442
443             // TODO This is temporary fix before deleting CreateByXaml flag in BindableProperty.
444             if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Tizen.NUI.BaseComponents.Selector<>) && valueType.GetGenericArguments()[0] == ReturnType)
445             {
446                 return true;
447             }
448
449             // Dont support arbitrary IConvertible by limiting which types can use this
450             Type[] convertableTo;
451             TypeConverter typeConverterTo;
452             if (SimpleConvertTypes.TryGetValue(valueType, out convertableTo) && Array.IndexOf(convertableTo, type) != -1)
453             {
454                 value = Convert.ChangeType(value, type);
455             }
456             else if (WellKnownConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
457             {
458                 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
459             }
460             else if (UserCustomConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
461             {
462                 //Modification for NUI XAML : user defined converter for DynamicResource can be added
463                 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
464             }
465             else if (!ReturnTypeInfo.IsAssignableFrom(valueType.GetTypeInfo()))
466             {
467                 var cast = type.GetImplicitConversionOperator(fromType: valueType, toType: type)
468                         ?? valueType.GetImplicitConversionOperator(fromType: valueType, toType: type);
469
470                 if (cast == null)
471                     return false;
472
473                 value = cast.Invoke(null, new[] { value });
474             }
475
476             return true;
477         }
478
479         internal delegate void BindablePropertyBindingChanging(BindableObject bindable, BindingBase oldValue, BindingBase newValue);
480     }
481 }