[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         /// Deprecated. Do not use.
323         /// </summary>
324         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
325         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
326         /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</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         [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
336         public static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
337                                                                         ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
338                                                                         BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
339                                                                         CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
340         {
341             return Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, defaultValueCreator: defaultValueCreator);
342         }
343
344         /// <summary>
345         /// Creates a new instance of the BindableProperty class.
346         /// </summary>
347         /// <param name="propertyName">The name of the BindableProperty.</param>
348         /// <param name="returnType">The type of the property.</param>
349         /// <param name="declaringType">The type of the declaring object.</param>
350         /// <param name="defaultValue">The default value for the property.</param>
351         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
352         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
353         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
354         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
355         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
356         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
357         /// <returns>A newly created BindableProperty.</returns>
358         public static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue = null, BindingMode defaultBindingMode = BindingMode.OneWay,
359                                               ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
360                                               CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
361         {
362             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
363                 defaultValueCreator: defaultValueCreator);
364         }
365
366         /// <summary>
367         /// Deprecated. Do not use.
368         /// </summary>
369         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
370         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
371         /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
372         /// <param name="defaultValue">The default value for the property.</param>
373         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
374         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
375         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
376         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
377         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
378         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
379         [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
380         public static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
381                                                                                 BindingMode defaultBindingMode = BindingMode.OneWay, ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
382                                                                                 BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
383                                                                                 CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
384         {
385             return CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null,
386                 defaultValueCreator: defaultValueCreator);
387         }
388
389         /// <summary>
390         /// Creates a new instance of the BindableProperty class for an attached property.
391         /// </summary>
392         /// <param name="propertyName">The name of the BindableProperty.</param>
393         /// <param name="returnType">The type of the property.</param>
394         /// <param name="declaringType">The type of the declaring object.</param>
395         /// <param name="defaultValue">The default value for the property.</param>
396         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
397         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
398         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
399         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
400         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
401         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
402         /// <returns>A newly created BindableProperty.</returns>
403         public static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
404                                                       ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
405                                                       CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
406         {
407             return CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false, defaultValueCreator);
408         }
409
410         /// <summary>
411         /// Deprecated. Do not use.
412         /// </summary>
413         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
414         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
415         /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
416         /// <param name="defaultValue">The default value for the property.</param>
417         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
418         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
419         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
420         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
421         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
422         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
423         /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
424         [Obsolete("CreateAttachedReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
425         public static BindablePropertyKey CreateAttachedReadOnly<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
426                                                                                            BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
427                                                                                            BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
428                                                                                            CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
429
430         {
431             return
432                 new BindablePropertyKey(CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
433                     defaultValueCreator));
434         }
435
436         /// <summary>
437         /// Creates a new instance of the BindableProperty class for attached read-only properties.
438         /// </summary>
439         /// <param name="propertyName">The name of the BindableProperty.</param>
440         /// <param name="returnType">The type of the property.</param>
441         /// <param name="declaringType">The type of the declaring object.</param>
442         /// <param name="defaultValue">The default value for the property.</param>
443         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
444         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
445         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
446         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
447         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
448         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
449         /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
450         public static BindablePropertyKey CreateAttachedReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
451                                                                  ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
452                                                                  CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
453         {
454             return
455                 new BindablePropertyKey(CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
456                     defaultValueCreator));
457         }
458
459         /// <summary>
460         /// Deprecated. Do not use.
461         /// </summary>
462         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
463         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
464         /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</param>
465         /// <param name="defaultValue">The default value for the property.</param>
466         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
467         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
468         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
469         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
470         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
471         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
472         /// <returns>A newly created BindablePropertyKey.</returns>
473         [Obsolete("CreateReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
474         public static BindablePropertyKey CreateReadOnly<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue,
475                                                                                    BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
476                                                                                    BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
477                                                                                    CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
478         {
479             return new BindablePropertyKey(Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true, defaultValueCreator));
480         }
481
482         /// <summary>
483         /// Creates a new instance of the BindablePropertyKey class.
484         /// </summary>
485         /// <param name="propertyName">The name of the BindableProperty.</param>
486         /// <param name="returnType">The type of the property.</param>
487         /// <param name="declaringType">The type of the declaring object.</param>
488         /// <param name="defaultValue">The default value for the property.</param>
489         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
490         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
491         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
492         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
493         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
494         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
495         /// <returns>A newly created BindablePropertyKey.</returns>
496         public static BindablePropertyKey CreateReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
497                                                          ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
498                                                          CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
499         {
500             return
501                 new BindablePropertyKey(new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
502                     isReadOnly: true, defaultValueCreator: defaultValueCreator));
503         }
504
505         [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
506         internal static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode,
507                                                                           ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
508                                                                           CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
509                                                                           CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
510         {
511             if (getter == null)
512                 throw new ArgumentNullException(nameof(getter));
513
514             Expression expr = getter.Body;
515
516             var unary = expr as UnaryExpression;
517             if (unary != null)
518                 expr = unary.Operand;
519
520             var member = expr as MemberExpression;
521             if (member == null)
522                 throw new ArgumentException("getter must be a MemberExpression", nameof(getter));
523
524             var property = (PropertyInfo)member.Member;
525
526             ValidateValueDelegate untypedValidateValue = null;
527             BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
528             BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
529             CoerceValueDelegate untypedCoerceValue = null;
530             CreateDefaultValueDelegate untypedDefaultValueCreator = null;
531             if (validateValue != null)
532                 untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
533             if (propertyChanged != null)
534                 untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
535             if (propertyChanging != null)
536                 untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
537             if (coerceValue != null)
538                 untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
539             if (defaultValueCreator != null)
540                 untypedDefaultValueCreator = o => defaultValueCreator((TDeclarer)o);
541
542             return new BindableProperty(property.Name, property.PropertyType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged,
543                 untypedBindingPropertyChanging, untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
544         }
545
546         internal static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
547                                                 BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
548                                                 CreateDefaultValueDelegate defaultValueCreator = null)
549         {
550             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging,
551                 defaultValueCreator: defaultValueCreator);
552         }
553
554         [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
555         internal static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue, BindingMode defaultBindingMode,
556                                                                                   ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
557                                                                                   CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
558                                                                                   CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
559         {
560             if (staticgetter == null)
561                 throw new ArgumentNullException(nameof(staticgetter));
562
563             Expression expr = staticgetter.Body;
564
565             var unary = expr as UnaryExpression;
566             if (unary != null)
567                 expr = unary.Operand;
568
569             var methodcall = expr as MethodCallExpression;
570             if (methodcall == null)
571                 throw new ArgumentException("staticgetter must be a MethodCallExpression", nameof(staticgetter));
572
573             MethodInfo method = methodcall.Method;
574             if (!method.Name.StartsWith("Get", StringComparison.Ordinal))
575                 throw new ArgumentException("staticgetter name must start with Get", nameof(staticgetter));
576
577             string propertyname = method.Name.Substring(3);
578
579             ValidateValueDelegate untypedValidateValue = null;
580             BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
581             BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
582             CoerceValueDelegate untypedCoerceValue = null;
583             CreateDefaultValueDelegate untypedDefaultValueCreator = null;
584             if (validateValue != null)
585                 untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
586             if (propertyChanged != null)
587                 untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
588             if (propertyChanging != null)
589                 untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
590             if (coerceValue != null)
591                 untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
592             if (defaultValueCreator != null)
593                 untypedDefaultValueCreator = o => defaultValueCreator(o);
594
595             return new BindableProperty(propertyname, method.ReturnType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged, untypedBindingPropertyChanging,
596                 untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
597         }
598
599         internal static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
600                                                         BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
601                                                         bool isReadOnly, CreateDefaultValueDelegate defaultValueCreator = null)
602         {
603             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, isReadOnly,
604                 defaultValueCreator);
605         }
606
607         internal object GetDefaultValue(BindableObject bindable)
608         {
609             if (DefaultValueCreator != null)
610                 return DefaultValueCreator(bindable);
611
612             return DefaultValue;
613         }
614
615         internal bool TryConvert(ref object value)
616         {
617             if (value == null)
618             {
619                 return !ReturnTypeInfo.IsValueType || ReturnTypeInfo.IsGenericType && ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
620             }
621
622             Type valueType = value.GetType();
623             Type type = ReturnType;
624
625             // TODO This is temporary fix before deleting CreateByXaml flag in BindableProperty.
626             if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(Tizen.NUI.BaseComponents.Selector<>) && valueType.GetGenericArguments()[0] == ReturnType)
627             {
628                 return true;
629             }
630
631             // Dont support arbitrary IConvertible by limiting which types can use this
632             Type[] convertableTo;
633             TypeConverter typeConverterTo;
634             if (SimpleConvertTypes.TryGetValue(valueType, out convertableTo) && Array.IndexOf(convertableTo, type) != -1)
635             {
636                 value = Convert.ChangeType(value, type);
637             }
638             else if (WellKnownConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
639             {
640                 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
641             }
642             else if (UserCustomConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
643             {
644                 //Modification for NUI XAML : user defined converter for DynamicResource can be added
645                 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
646             }
647             else if (!ReturnTypeInfo.IsAssignableFrom(valueType.GetTypeInfo()))
648             {
649                 var cast = type.GetImplicitConversionOperator(fromType: valueType, toType: type)
650                         ?? valueType.GetImplicitConversionOperator(fromType: valueType, toType: type);
651
652                 if (cast == null)
653                     return false;
654
655                 value = cast.Invoke(null, new[] { value });
656             }
657
658             return true;
659         }
660
661         internal delegate void BindablePropertyBindingChanging(BindableObject bindable, BindingBase oldValue, BindingBase newValue);
662     }
663 }