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