[NUI] Adjust directory (#903)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / XamlBinding / BindableProperty.cs
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Linq.Expressions;
5 using System.Reflection;
6 using System.ComponentModel;
7 using Tizen.NUI.Binding.Internals;
8 using Tizen.NUI.Xaml;
9
10 namespace Tizen.NUI.Binding
11 {
12     /// <summary>
13     /// A BindableProperty is a backing store for properties allowing bindings on BindableObject.
14     /// </summary>
15     [DebuggerDisplay("{PropertyName}")]
16     [TypeConverter(typeof(BindablePropertyConverter))]
17     [EditorBrowsable(EditorBrowsableState.Never)]
18     public sealed class BindableProperty
19     {
20         /// <summary>
21         /// Delegate for BindableProperty.PropertyChanged.
22         /// </summary>
23         /// <param name="bindable">The bindable object that contains the property.</param>
24         /// <param name="oldValue">The old property value.</param>
25         /// <param name="newValue">The new property value.</param>
26         public delegate void BindingPropertyChangedDelegate(BindableObject bindable, object oldValue, object newValue);
27
28         /// <summary>
29         /// Strongly-typed delegate for BindableProperty.PropertyChanged.
30         /// </summary>
31         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
32         /// <param name="bindable">The bindable object that contains the property.</param>
33         /// <param name="oldValue">The old property value.</param>
34         /// <param name="newValue">The new property value.</param>
35         public delegate void BindingPropertyChangedDelegate<in TPropertyType>(BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
36
37         /// <summary>
38         /// Delegate for BindableProperty.PropertyChanging.
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 BindingPropertyChangingDelegate(BindableObject bindable, object oldValue, object newValue);
44
45         /// <summary>
46         /// Strongly-typed delegate for BindableProperty.PropertyChanging.
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 BindingPropertyChangingDelegate<in TPropertyType>(BindableObject bindable, TPropertyType oldValue, TPropertyType newValue);
53
54         /// <summary>
55         /// Delegate for BindableProperty.CoerceValue.
56         /// </summary>
57         /// <param name="bindable">The bindable object that contains the property.</param>
58         /// <param name="value">The value to coerce.</param>
59         /// <returns>System.Object</returns>
60         public delegate object CoerceValueDelegate(BindableObject bindable, object value);
61
62         /// <summary>
63         /// Strongly-typed delegate for BindableProperty.CoerceValue.
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="value">The value to coerce.</param>
68         /// <returns>TPropertyType</returns>
69         public delegate TPropertyType CoerceValueDelegate<TPropertyType>(BindableObject bindable, TPropertyType value);
70
71         /// <summary>
72         /// Delegate for BindableProperty.DefaultValueCreator.
73         /// </summary>
74         /// <param name="bindable">The bindable object that contains the property.</param>
75         /// <returns>System.Object</returns>
76         public delegate object CreateDefaultValueDelegate(BindableObject bindable);
77
78         /// <summary>
79         /// Strongly-typed delegate for BindableProperty.DefaultValueCreator.
80         /// </summary>
81         /// <typeparam name="TDeclarer">The type of the object that delared the property.</typeparam>
82         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
83         /// <param name="bindable">The bindable object that contains the property.</param>
84         /// <returns>TPropertyType</returns>
85         public delegate TPropertyType CreateDefaultValueDelegate<in TDeclarer, out TPropertyType>(TDeclarer bindable);
86
87         /// <summary>
88         /// Delegate for BindableProperty.ValidateValue.
89         /// </summary>
90         /// <param name="bindable">The bindable object that contains the property.</param>
91         /// <param name="value">The default value.</param>
92         /// <returns>System.Boolean</returns>
93         public delegate bool ValidateValueDelegate(BindableObject bindable, object value);
94
95         /// <summary>
96         /// Strongly-typed delegate for BindableProperty.ValidateValue.
97         /// </summary>
98         /// <typeparam name="TPropertyType">The type of the bound property.</typeparam>
99         /// <param name="bindable">The bindable object that contains the property.</param>
100         /// <param name="value">The default value.</param>
101         /// <returns>System.Boolean</returns>
102         public delegate bool ValidateValueDelegate<in TPropertyType>(BindableObject bindable, TPropertyType value);
103
104         static readonly Dictionary<Type, TypeConverter> WellKnownConvertTypes = new  Dictionary<Type,TypeConverter>
105         {
106             { typeof(Uri), new UriTypeConverter() },
107             { typeof(Color), new ColorTypeConverter() },
108             { typeof(Size2D), new Size2DTypeConverter() },
109             { typeof(Position2D), new Position2DTypeConverter() },
110             { typeof(Size), new SizeTypeConverter() },
111             { typeof(Position), new PositionTypeConverter() },
112             { typeof(Rectangle), new RectangleTypeConverter() },
113             { typeof(Rotation), new RotationTypeConverter() },
114             { typeof(Vector2), new Vector2TypeConverter() },
115             { typeof(Vector3), new Vector3TypeConverter() },
116             { typeof(Vector4), new Vector4TypeConverter() },
117             { typeof(RelativeVector2), new RelativeVector2TypeConverter() },
118             { typeof(RelativeVector3), new RelativeVector3TypeConverter() },
119             { typeof(RelativeVector4), new RelativeVector4TypeConverter() },
120         };
121
122         //Modification for NUI XAML : user defined converter for DynamicResource can be added
123         static internal Dictionary<Type, TypeConverter> UserCustomConvertTypes = new Dictionary<Type, TypeConverter>
124         {
125         };
126
127         // more or less the encoding of this, without the need to reflect
128         // http://msdn.microsoft.com/en-us/library/y5b434w4.aspx
129         static readonly Dictionary<Type, Type[]> SimpleConvertTypes = new Dictionary<Type, Type[]>
130         {
131             { typeof(sbyte), new[] { typeof(string), typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
132             { typeof(byte), new[] { typeof(string), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
133             { typeof(short), new[] { typeof(string), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
134             { typeof(ushort), new[] { typeof(string), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
135             { typeof(int), new[] { typeof(string), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
136             { typeof(uint), new[] { typeof(string), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
137             { typeof(long), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } },
138             { typeof(char), new[] { typeof(string), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
139             { typeof(float), new[] { typeof(string), typeof(double) } },
140             { typeof(ulong), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } }
141         };
142
143         BindableProperty(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
144                                  ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
145                                  CoerceValueDelegate coerceValue = null, BindablePropertyBindingChanging bindingChanging = null, bool isReadOnly = false, CreateDefaultValueDelegate defaultValueCreator = null)
146         {
147             if (propertyName == null)
148                 throw new ArgumentNullException("propertyName");
149             if (ReferenceEquals(returnType, null))
150                 throw new ArgumentNullException("returnType");
151             if (ReferenceEquals(declaringType, null))
152                 throw new ArgumentNullException("declaringType");
153
154             // don't use Enum.IsDefined as its redonkulously expensive for what it does
155             if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay && defaultBindingMode != BindingMode.OneTime)
156                 throw new ArgumentException("Not a valid type of BindingMode", "defaultBindingMode");
157             if (defaultValue == null && Nullable.GetUnderlyingType(returnType) == null && returnType.GetTypeInfo().IsValueType)
158                 throw new ArgumentException("Not a valid default value", "defaultValue");
159             if (defaultValue != null && !returnType.IsInstanceOfType(defaultValue))
160                 throw new ArgumentException("Default value did not match return type", "defaultValue");
161             if (defaultBindingMode == BindingMode.Default)
162                 defaultBindingMode = BindingMode.OneWay;
163
164             PropertyName = propertyName;
165             ReturnType = returnType;
166             ReturnTypeInfo = returnType.GetTypeInfo();
167             DeclaringType = declaringType;
168             DefaultValue = defaultValue;
169             DefaultBindingMode = defaultBindingMode;
170             PropertyChanged = propertyChanged;
171             PropertyChanging = propertyChanging;
172             ValidateValue = validateValue;
173             CoerceValue = coerceValue;
174             BindingChanging = bindingChanging;
175             IsReadOnly = isReadOnly;
176             DefaultValueCreator = defaultValueCreator;
177         }
178
179         /// <summary>
180         /// Gets the type declaring the BindableProperty.
181         /// </summary>
182         public Type DeclaringType { get; private set; }
183
184         /// <summary>
185         /// Gets the default BindingMode.
186         /// </summary>
187         public BindingMode DefaultBindingMode { get; private set; }
188
189         /// <summary>
190         /// Gets the default value for the BindableProperty.
191         /// </summary>
192         public object DefaultValue { get; }
193
194         /// <summary>
195         /// Gets a value indicating if the BindableProperty is created form a BindablePropertyKey.
196         /// </summary>
197         public bool IsReadOnly { get; private set; }
198
199         /// <summary>
200         /// Gets the property name.
201         /// </summary>
202         public string PropertyName { get; }
203
204         /// <summary>
205         /// Gets the type of the BindableProperty.
206         /// </summary>
207         public Type ReturnType { get; }
208
209         internal BindablePropertyBindingChanging BindingChanging { get; private set; }
210
211         internal CoerceValueDelegate CoerceValue { get; private set; }
212
213         internal CreateDefaultValueDelegate DefaultValueCreator { get; }
214
215         internal BindingPropertyChangedDelegate PropertyChanged { get; private set; }
216
217         internal BindingPropertyChangingDelegate PropertyChanging { get; private set; }
218
219         internal System.Reflection.TypeInfo ReturnTypeInfo { get; }
220
221         internal ValidateValueDelegate ValidateValue { get; private set; }
222
223         /// <summary>
224         /// Deprecated. Do not use.
225         /// </summary>
226         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
227         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
228         /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</param>
229         /// <param name="defaultValue">The default value for the property.</param>
230         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
231         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
232         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
233         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
234         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
235         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
236         /// <returns>A newly created BindableProperty.</returns>
237         [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
238         public static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
239                                                                         ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
240                                                                         BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
241                                                                         CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
242         {
243             return Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, defaultValueCreator: defaultValueCreator);
244         }
245
246         /// <summary>
247         /// Creates a new instance of the BindableProperty class.
248         /// </summary>
249         /// <param name="propertyName">The name of the BindableProperty.</param>
250         /// <param name="returnType">The type of the property.</param>
251         /// <param name="declaringType">The type of the declaring object.</param>
252         /// <param name="defaultValue">The default value for the property.</param>
253         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
254         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
255         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
256         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
257         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
258         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
259         /// <returns>A newly created BindableProperty.</returns>
260         public static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue = null, BindingMode defaultBindingMode = BindingMode.OneWay,
261                                               ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
262                                               CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
263         {
264             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
265                 defaultValueCreator: defaultValueCreator);
266         }
267
268         /// <summary>
269         /// Deprecated. Do not use.
270         /// </summary>
271         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
272         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
273         /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
274         /// <param name="defaultValue">The default value for the property.</param>
275         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
276         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
277         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
278         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
279         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
280         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
281         [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
282         public static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
283                                                                                 BindingMode defaultBindingMode = BindingMode.OneWay, ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
284                                                                                 BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
285                                                                                 CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
286         {
287             return CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null,
288                 defaultValueCreator: defaultValueCreator);
289         }
290
291         /// <summary>
292         /// Creates a new instance of the BindableProperty class for an attached property.
293         /// </summary>
294         /// <param name="propertyName">The name of the BindableProperty.</param>
295         /// <param name="returnType">The type of the property.</param>
296         /// <param name="declaringType">The type of the declaring object.</param>
297         /// <param name="defaultValue">The default value for the property.</param>
298         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
299         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
300         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
301         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
302         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
303         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
304         /// <returns>A newly created BindableProperty.</returns>
305         public static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
306                                                       ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
307                                                       CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
308         {
309             return CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false, defaultValueCreator);
310         }
311
312         /// <summary>
313         /// Deprecated. Do not use.
314         /// </summary>
315         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
316         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
317         /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
318         /// <param name="defaultValue">The default value for the property.</param>
319         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
320         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
321         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
322         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
323         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
324         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
325         /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
326         [Obsolete("CreateAttachedReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
327         public static BindablePropertyKey CreateAttachedReadOnly<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
328                                                                                            BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
329                                                                                            BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
330                                                                                            CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
331
332         {
333             return
334                 new BindablePropertyKey(CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
335                     defaultValueCreator));
336         }
337
338         /// <summary>
339         /// Creates a new instance of the BindableProperty class for attached read-only properties.
340         /// </summary>
341         /// <param name="propertyName">The name of the BindableProperty.</param>
342         /// <param name="returnType">The type of the property.</param>
343         /// <param name="declaringType">The type of the declaring object.</param>
344         /// <param name="defaultValue">The default value for the property.</param>
345         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
346         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
347         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
348         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
349         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
350         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
351         /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
352         public static BindablePropertyKey CreateAttachedReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
353                                                                  ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
354                                                                  CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
355         {
356             return
357                 new BindablePropertyKey(CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
358                     defaultValueCreator));
359         }
360
361         /// <summary>
362         /// Deprecated. Do not use.
363         /// </summary>
364         /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
365         /// <typeparam name="TPropertyType">The type of the property.</typeparam>
366         /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</param>
367         /// <param name="defaultValue">The default value for the property.</param>
368         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
369         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
370         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
371         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
372         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
373         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
374         /// <returns>A newly created BindablePropertyKey.</returns>
375         [Obsolete("CreateReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
376         public static BindablePropertyKey CreateReadOnly<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue,
377                                                                                    BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
378                                                                                    BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
379                                                                                    CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
380         {
381             return new BindablePropertyKey(Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true, defaultValueCreator));
382         }
383
384         /// <summary>
385         /// Creates a new instance of the BindablePropertyKey class.
386         /// </summary>
387         /// <param name="propertyName">The name of the BindableProperty.</param>
388         /// <param name="returnType">The type of the property.</param>
389         /// <param name="declaringType">The type of the declaring object.</param>
390         /// <param name="defaultValue">The default value for the property.</param>
391         /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
392         /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
393         /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
394         /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
395         /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
396         /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
397         /// <returns>A newly created BindablePropertyKey.</returns>
398         public static BindablePropertyKey CreateReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
399                                                          ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
400                                                          CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
401         {
402             return
403                 new BindablePropertyKey(new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
404                     isReadOnly: true, defaultValueCreator: defaultValueCreator));
405         }
406
407         [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
408         internal static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode,
409                                                                           ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
410                                                                           CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
411                                                                           CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
412         {
413             if (getter == null)
414                 throw new ArgumentNullException("getter");
415
416             Expression expr = getter.Body;
417
418             var unary = expr as UnaryExpression;
419             if (unary != null)
420                 expr = unary.Operand;
421
422             var member = expr as MemberExpression;
423             if (member == null)
424                 throw new ArgumentException("getter must be a MemberExpression", "getter");
425
426             var property = (PropertyInfo)member.Member;
427
428             ValidateValueDelegate untypedValidateValue = null;
429             BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
430             BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
431             CoerceValueDelegate untypedCoerceValue = null;
432             CreateDefaultValueDelegate untypedDefaultValueCreator = null;
433             if (validateValue != null)
434                 untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
435             if (propertyChanged != null)
436                 untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
437             if (propertyChanging != null)
438                 untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
439             if (coerceValue != null)
440                 untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
441             if (defaultValueCreator != null)
442                 untypedDefaultValueCreator = o => defaultValueCreator((TDeclarer)o);
443
444             return new BindableProperty(property.Name, property.PropertyType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged,
445                 untypedBindingPropertyChanging, untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
446         }
447
448         internal static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
449                                                 BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
450                                                 CreateDefaultValueDelegate defaultValueCreator = null)
451         {
452             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging,
453                 defaultValueCreator: defaultValueCreator);
454         }
455
456         [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
457         internal static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue, BindingMode defaultBindingMode,
458                                                                                   ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
459                                                                                   CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
460                                                                                   CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
461         {
462             if (staticgetter == null)
463                 throw new ArgumentNullException("staticgetter");
464
465             Expression expr = staticgetter.Body;
466
467             var unary = expr as UnaryExpression;
468             if (unary != null)
469                 expr = unary.Operand;
470
471             var methodcall = expr as MethodCallExpression;
472             if (methodcall == null)
473                 throw new ArgumentException("staticgetter must be a MethodCallExpression", "staticgetter");
474
475             MethodInfo method = methodcall.Method;
476             if (!method.Name.StartsWith("Get", StringComparison.Ordinal))
477                 throw new ArgumentException("staticgetter name must start with Get", "staticgetter");
478
479             string propertyname = method.Name.Substring(3);
480
481             ValidateValueDelegate untypedValidateValue = null;
482             BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
483             BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
484             CoerceValueDelegate untypedCoerceValue = null;
485             CreateDefaultValueDelegate untypedDefaultValueCreator = null;
486             if (validateValue != null)
487                 untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
488             if (propertyChanged != null)
489                 untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
490             if (propertyChanging != null)
491                 untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
492             if (coerceValue != null)
493                 untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
494             if (defaultValueCreator != null)
495                 untypedDefaultValueCreator = o => defaultValueCreator(o);
496
497             return new BindableProperty(propertyname, method.ReturnType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged, untypedBindingPropertyChanging,
498                 untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
499         }
500
501         internal static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
502                                                         BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
503                                                         bool isReadOnly, CreateDefaultValueDelegate defaultValueCreator = null)
504         {
505             return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, isReadOnly,
506                 defaultValueCreator);
507         }
508
509         internal object GetDefaultValue(BindableObject bindable)
510         {
511             if (DefaultValueCreator != null)
512                 return DefaultValueCreator(bindable);
513
514             return DefaultValue;
515         }
516
517         internal bool TryConvert(ref object value)
518         {
519             if (value == null)
520             {
521                 return !ReturnTypeInfo.IsValueType || ReturnTypeInfo.IsGenericType && ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
522             }
523
524             Type valueType = value.GetType();
525             Type type = ReturnType;
526
527             // Dont support arbitrary IConvertible by limiting which types can use this
528             Type[] convertableTo;
529             TypeConverter typeConverterTo;
530             if (SimpleConvertTypes.TryGetValue(valueType, out convertableTo) && Array.IndexOf(convertableTo, type) != -1)
531             {
532                 value = Convert.ChangeType(value, type);
533             }
534             else if (WellKnownConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
535             {
536                 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
537             }
538             else if (UserCustomConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
539             {
540                 //Modification for NUI XAML : user defined converter for DynamicResource can be added
541                 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
542             }
543             else if (!ReturnTypeInfo.IsAssignableFrom(valueType.GetTypeInfo()))
544             {
545                 var cast = type.GetImplicitConversionOperator(fromType: valueType, toType: type)
546                         ?? valueType.GetImplicitConversionOperator(fromType: valueType, toType: type);
547
548                 if (cast == null)
549                     return false;
550
551                 value = cast.Invoke(null, new[] { value });
552             }
553
554             return true;
555         }
556
557         internal delegate void BindablePropertyBindingChanging(BindableObject bindable, BindingBase oldValue, BindingBase newValue);
558     }
559 }