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