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;
10 namespace Tizen.NUI.Binding
13 /// A BindableProperty is a backing store for properties allowing bindings on BindableObject.
15 [DebuggerDisplay("{PropertyName}")]
16 [TypeConverter(typeof(BindablePropertyConverter))]
17 [EditorBrowsable(EditorBrowsableState.Never)]
18 public sealed class BindableProperty
21 /// Delegate for BindableProperty.PropertyChanged.
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);
29 /// Strongly-typed delegate for BindableProperty.PropertyChanged.
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);
38 /// Delegate for BindableProperty.PropertyChanging.
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);
46 /// Strongly-typed delegate for BindableProperty.PropertyChanging.
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);
55 /// Delegate for BindableProperty.CoerceValue.
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);
63 /// Strongly-typed delegate for BindableProperty.CoerceValue.
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);
72 /// Delegate for BindableProperty.DefaultValueCreator.
74 /// <param name="bindable">The bindable object that contains the property.</param>
75 /// <returns>System.Object</returns>
76 public delegate object CreateDefaultValueDelegate(BindableObject bindable);
79 /// Strongly-typed delegate for BindableProperty.DefaultValueCreator.
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);
88 /// Delegate for BindableProperty.ValidateValue.
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);
96 /// Strongly-typed delegate for BindableProperty.ValidateValue.
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);
104 //To confirm the static dictionary will be created before the constructor is called.
105 static BindableProperty()
109 static readonly Dictionary<Type, TypeConverter> WellKnownConvertTypes = new Dictionary<Type,TypeConverter>
111 { typeof(Uri), new UriTypeConverter() },
112 { typeof(Color), new ColorTypeConverter() },
113 { typeof(Size2D), new Size2DTypeConverter() },
114 { typeof(Position2D), new Position2DTypeConverter() },
115 { typeof(Size), new SizeTypeConverter() },
116 { typeof(Position), new PositionTypeConverter() },
117 { typeof(Rectangle), new RectangleTypeConverter() },
118 { typeof(Rotation), new RotationTypeConverter() },
119 { typeof(Vector2), new Vector2TypeConverter() },
120 { typeof(Vector3), new Vector3TypeConverter() },
121 { typeof(Vector4), new Vector4TypeConverter() },
122 { typeof(RelativeVector2), new RelativeVector2TypeConverter() },
123 { typeof(RelativeVector3), new RelativeVector3TypeConverter() },
124 { typeof(RelativeVector4), new RelativeVector4TypeConverter() },
127 //Modification for NUI XAML : user defined converter for DynamicResource can be added
128 static internal Dictionary<Type, TypeConverter> UserCustomConvertTypes = new Dictionary<Type, TypeConverter>
132 // more or less the encoding of this, without the need to reflect
133 // http://msdn.microsoft.com/en-us/library/y5b434w4.aspx
134 static readonly Dictionary<Type, Type[]> SimpleConvertTypes = new Dictionary<Type, Type[]>
136 { typeof(sbyte), new[] { typeof(string), typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
137 { typeof(byte), new[] { typeof(string), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
138 { typeof(short), new[] { typeof(string), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
139 { typeof(ushort), new[] { typeof(string), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
140 { typeof(int), new[] { typeof(string), typeof(long), typeof(float), typeof(double), typeof(decimal) } },
141 { typeof(uint), new[] { typeof(string), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
142 { typeof(long), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } },
143 { typeof(char), new[] { typeof(string), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) } },
144 { typeof(float), new[] { typeof(string), typeof(double) } },
145 { typeof(ulong), new[] { typeof(string), typeof(float), typeof(double), typeof(decimal) } }
148 BindableProperty(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
149 ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
150 CoerceValueDelegate coerceValue = null, BindablePropertyBindingChanging bindingChanging = null, bool isReadOnly = false, CreateDefaultValueDelegate defaultValueCreator = null)
152 if (propertyName == null)
153 throw new ArgumentNullException(nameof(propertyName));
154 if (ReferenceEquals(returnType, null))
155 throw new ArgumentNullException(nameof(returnType));
156 if (ReferenceEquals(declaringType, null))
157 throw new ArgumentNullException(nameof(declaringType));
159 // don't use Enum.IsDefined as its redonkulously expensive for what it does
160 if (defaultBindingMode != BindingMode.Default && defaultBindingMode != BindingMode.OneWay && defaultBindingMode != BindingMode.OneWayToSource && defaultBindingMode != BindingMode.TwoWay && defaultBindingMode != BindingMode.OneTime)
161 throw new ArgumentException("Not a valid type of BindingMode", nameof(defaultBindingMode));
162 if (defaultValue == null && Nullable.GetUnderlyingType(returnType) == null && returnType.GetTypeInfo().IsValueType)
163 throw new ArgumentException("Not a valid default value", nameof(defaultValue));
164 if (defaultValue != null && !returnType.IsInstanceOfType(defaultValue))
165 throw new ArgumentException("Default value did not match return type", nameof(defaultValue));
166 if (defaultBindingMode == BindingMode.Default)
167 defaultBindingMode = BindingMode.OneWay;
169 PropertyName = propertyName;
170 ReturnType = returnType;
171 ReturnTypeInfo = returnType.GetTypeInfo();
172 DeclaringType = declaringType;
173 DefaultValue = defaultValue;
174 DefaultBindingMode = defaultBindingMode;
175 PropertyChanged = propertyChanged;
176 PropertyChanging = propertyChanging;
177 ValidateValue = validateValue;
178 CoerceValue = coerceValue;
179 BindingChanging = bindingChanging;
180 IsReadOnly = isReadOnly;
181 DefaultValueCreator = defaultValueCreator;
183 Dictionary<string, BindableProperty> nameToBindableProperty;
184 bindablePropertyOfType.TryGetValue(declaringType, out nameToBindableProperty);
185 if (null == nameToBindableProperty)
187 nameToBindableProperty = new Dictionary<string, BindableProperty>();
188 bindablePropertyOfType.Add(declaringType, nameToBindableProperty);
191 if (!nameToBindableProperty.ContainsKey(propertyName))
193 nameToBindableProperty.Add(propertyName, this);
197 nameToBindableProperty[propertyName] = this;
201 private static bool AddParentTypeProperty(Type type, Dictionary<string, BindableProperty> propertyDict)
207 Dictionary<string, BindableProperty> nameToBindableProperty;
208 bindablePropertyOfType.TryGetValue(type, out nameToBindableProperty);
210 if (null != nameToBindableProperty)
214 foreach (KeyValuePair<string, BindableProperty> keyValuePair in nameToBindableProperty)
216 if (!propertyDict.ContainsKey(keyValuePair.Key))
218 propertyDict.Add(keyValuePair.Key, keyValuePair.Value);
223 if (true == AddParentTypeProperty(type.BaseType, propertyDict))
232 static internal Dictionary<Type, Dictionary<string, BindableProperty>> bindablePropertyOfType = new Dictionary<Type, Dictionary<string, BindableProperty>>();
233 static private HashSet<Type> baseTypePropertyHasBeenAdded = new HashSet<Type>();
235 static internal void GetBindablePropertysOfType(Type type, out Dictionary<string, BindableProperty> dictionary)
239 bindablePropertyOfType.TryGetValue(type, out dictionary);
241 if (!baseTypePropertyHasBeenAdded.Contains(type))
243 bool isCurDictNull = false;
245 if (null == dictionary)
247 isCurDictNull = true;
248 dictionary = new Dictionary<string, BindableProperty>();
251 if (true == AddParentTypeProperty(type.BaseType, dictionary) && true == isCurDictNull)
253 bindablePropertyOfType.Add(type, dictionary);
256 baseTypePropertyHasBeenAdded.Add(type);
261 /// Gets the type declaring the BindableProperty.
263 public Type DeclaringType { get; private set; }
266 /// Gets the default BindingMode.
268 public BindingMode DefaultBindingMode { get; private set; }
271 /// Gets the default value for the BindableProperty.
273 public object DefaultValue { get; }
276 /// Gets a value indicating if the BindableProperty is created form a BindablePropertyKey.
278 public bool IsReadOnly { get; private set; }
281 /// Gets the property name.
283 public string PropertyName { get; }
286 /// Gets the type of the BindableProperty.
288 public Type ReturnType { get; }
290 internal BindablePropertyBindingChanging BindingChanging { get; private set; }
292 internal CoerceValueDelegate CoerceValue { get; private set; }
294 internal CreateDefaultValueDelegate DefaultValueCreator { get; }
296 internal BindingPropertyChangedDelegate PropertyChanged { get; private set; }
298 internal BindingPropertyChangingDelegate PropertyChanging { get; private set; }
300 internal System.Reflection.TypeInfo ReturnTypeInfo { get; }
302 internal ValidateValueDelegate ValidateValue { get; private set; }
305 /// Deprecated. Do not use.
307 /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
308 /// <typeparam name="TPropertyType">The type of the property.</typeparam>
309 /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</param>
310 /// <param name="defaultValue">The default value for the property.</param>
311 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
312 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
313 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
314 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
315 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
316 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
317 /// <returns>A newly created BindableProperty.</returns>
318 [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
319 public static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
320 ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
321 BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
322 CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
324 return Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, defaultValueCreator: defaultValueCreator);
328 /// Creates a new instance of the BindableProperty class.
330 /// <param name="propertyName">The name of the BindableProperty.</param>
331 /// <param name="returnType">The type of the property.</param>
332 /// <param name="declaringType">The type of the declaring object.</param>
333 /// <param name="defaultValue">The default value for the property.</param>
334 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
335 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
336 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
337 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
338 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
339 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
340 /// <returns>A newly created BindableProperty.</returns>
341 public static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue = null, BindingMode defaultBindingMode = BindingMode.OneWay,
342 ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
343 CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
345 return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
346 defaultValueCreator: defaultValueCreator);
350 /// Deprecated. Do not use.
352 /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
353 /// <typeparam name="TPropertyType">The type of the property.</typeparam>
354 /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
355 /// <param name="defaultValue">The default value for the property.</param>
356 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
357 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
358 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
359 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
360 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
361 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
362 [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
363 public static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
364 BindingMode defaultBindingMode = BindingMode.OneWay, ValidateValueDelegate<TPropertyType> validateValue = null, BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null,
365 BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null, CoerceValueDelegate<TPropertyType> coerceValue = null,
366 CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
368 return CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null,
369 defaultValueCreator: defaultValueCreator);
373 /// Creates a new instance of the BindableProperty class for an attached property.
375 /// <param name="propertyName">The name of the BindableProperty.</param>
376 /// <param name="returnType">The type of the property.</param>
377 /// <param name="declaringType">The type of the declaring object.</param>
378 /// <param name="defaultValue">The default value for the property.</param>
379 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
380 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
381 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
382 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
383 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
384 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
385 /// <returns>A newly created BindableProperty.</returns>
386 public static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWay,
387 ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
388 CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
390 return CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, false, defaultValueCreator);
394 /// Deprecated. Do not use.
396 /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
397 /// <typeparam name="TPropertyType">The type of the property.</typeparam>
398 /// <param name="staticgetter">An expression identifying a static method returning the value of the property using this BindableProperty as backing store.</param>
399 /// <param name="defaultValue">The default value for the property.</param>
400 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
401 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
402 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
403 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
404 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
405 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
406 /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
407 [Obsolete("CreateAttachedReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
408 public static BindablePropertyKey CreateAttachedReadOnly<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue,
409 BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
410 BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
411 CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
415 new BindablePropertyKey(CreateAttached<TDeclarer, TPropertyType>(staticgetter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
416 defaultValueCreator));
420 /// Creates a new instance of the BindableProperty class for attached read-only properties.
422 /// <param name="propertyName">The name of the BindableProperty.</param>
423 /// <param name="returnType">The type of the property.</param>
424 /// <param name="declaringType">The type of the declaring object.</param>
425 /// <param name="defaultValue">The default value for the property.</param>
426 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
427 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
428 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
429 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
430 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
431 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
432 /// <returns>A newly created attached read-only BindablePropertyKey.</returns>
433 public static BindablePropertyKey CreateAttachedReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
434 ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
435 CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
438 new BindablePropertyKey(CreateAttached(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true,
439 defaultValueCreator));
443 /// Deprecated. Do not use.
445 /// <typeparam name="TDeclarer">The type of the declaring object.</typeparam>
446 /// <typeparam name="TPropertyType">The type of the property.</typeparam>
447 /// <param name="getter">An expression identifying the getter for the property using this BindableProperty as backing store.</param>
448 /// <param name="defaultValue">The default value for the property.</param>
449 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
450 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
451 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
452 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
453 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
454 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
455 /// <returns>A newly created BindablePropertyKey.</returns>
456 [Obsolete("CreateReadOnly<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
457 public static BindablePropertyKey CreateReadOnly<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue,
458 BindingMode defaultBindingMode = BindingMode.OneWayToSource, ValidateValueDelegate<TPropertyType> validateValue = null,
459 BindingPropertyChangedDelegate<TPropertyType> propertyChanged = null, BindingPropertyChangingDelegate<TPropertyType> propertyChanging = null,
460 CoerceValueDelegate<TPropertyType> coerceValue = null, CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
462 return new BindablePropertyKey(Create(getter, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, null, true, defaultValueCreator));
466 /// Creates a new instance of the BindablePropertyKey class.
468 /// <param name="propertyName">The name of the BindableProperty.</param>
469 /// <param name="returnType">The type of the property.</param>
470 /// <param name="declaringType">The type of the declaring object.</param>
471 /// <param name="defaultValue">The default value for the property.</param>
472 /// <param name="defaultBindingMode">The BindingMode to use on SetBinding() if no BindingMode is given. This parameter is optional. Default is BindingMode.OneWay.</param>
473 /// <param name="validateValue">A delegate to be run when a value is set. This parameter is optional. Default is null.</param>
474 /// <param name="propertyChanged">A delegate to be run when the value has changed. This parameter is optional. Default is null.</param>
475 /// <param name="propertyChanging">A delegate to be run when the value will change. This parameter is optional. Default is null.</param>
476 /// <param name="coerceValue">A delegate used to coerce the range of a value. This parameter is optional. Default is null.</param>
477 /// <param name="defaultValueCreator">A Func used to initialize default value for reference types.</param>
478 /// <returns>A newly created BindablePropertyKey.</returns>
479 public static BindablePropertyKey CreateReadOnly(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode = BindingMode.OneWayToSource,
480 ValidateValueDelegate validateValue = null, BindingPropertyChangedDelegate propertyChanged = null, BindingPropertyChangingDelegate propertyChanging = null,
481 CoerceValueDelegate coerceValue = null, CreateDefaultValueDelegate defaultValueCreator = null)
484 new BindablePropertyKey(new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue,
485 isReadOnly: true, defaultValueCreator: defaultValueCreator));
488 [Obsolete("Create<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
489 internal static BindableProperty Create<TDeclarer, TPropertyType>(Expression<Func<TDeclarer, TPropertyType>> getter, TPropertyType defaultValue, BindingMode defaultBindingMode,
490 ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
491 CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
492 CreateDefaultValueDelegate<TDeclarer, TPropertyType> defaultValueCreator = null) where TDeclarer : BindableObject
495 throw new ArgumentNullException(nameof(getter));
497 Expression expr = getter.Body;
499 var unary = expr as UnaryExpression;
501 expr = unary.Operand;
503 var member = expr as MemberExpression;
505 throw new ArgumentException("getter must be a MemberExpression", nameof(getter));
507 var property = (PropertyInfo)member.Member;
509 ValidateValueDelegate untypedValidateValue = null;
510 BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
511 BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
512 CoerceValueDelegate untypedCoerceValue = null;
513 CreateDefaultValueDelegate untypedDefaultValueCreator = null;
514 if (validateValue != null)
515 untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
516 if (propertyChanged != null)
517 untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
518 if (propertyChanging != null)
519 untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
520 if (coerceValue != null)
521 untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
522 if (defaultValueCreator != null)
523 untypedDefaultValueCreator = o => defaultValueCreator((TDeclarer)o);
525 return new BindableProperty(property.Name, property.PropertyType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged,
526 untypedBindingPropertyChanging, untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
529 internal static BindableProperty Create(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
530 BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
531 CreateDefaultValueDelegate defaultValueCreator = null)
533 return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging,
534 defaultValueCreator: defaultValueCreator);
537 [Obsolete("CreateAttached<> (generic) is obsolete as of version 2.1.0 and is no longer supported.")]
538 internal static BindableProperty CreateAttached<TDeclarer, TPropertyType>(Expression<Func<BindableObject, TPropertyType>> staticgetter, TPropertyType defaultValue, BindingMode defaultBindingMode,
539 ValidateValueDelegate<TPropertyType> validateValue, BindingPropertyChangedDelegate<TPropertyType> propertyChanged, BindingPropertyChangingDelegate<TPropertyType> propertyChanging,
540 CoerceValueDelegate<TPropertyType> coerceValue, BindablePropertyBindingChanging bindingChanging, bool isReadOnly = false,
541 CreateDefaultValueDelegate<BindableObject, TPropertyType> defaultValueCreator = null)
543 if (staticgetter == null)
544 throw new ArgumentNullException(nameof(staticgetter));
546 Expression expr = staticgetter.Body;
548 var unary = expr as UnaryExpression;
550 expr = unary.Operand;
552 var methodcall = expr as MethodCallExpression;
553 if (methodcall == null)
554 throw new ArgumentException("staticgetter must be a MethodCallExpression", nameof(staticgetter));
556 MethodInfo method = methodcall.Method;
557 if (!method.Name.StartsWith("Get", StringComparison.Ordinal))
558 throw new ArgumentException("staticgetter name must start with Get", nameof(staticgetter));
560 string propertyname = method.Name.Substring(3);
562 ValidateValueDelegate untypedValidateValue = null;
563 BindingPropertyChangedDelegate untypedBindingPropertyChanged = null;
564 BindingPropertyChangingDelegate untypedBindingPropertyChanging = null;
565 CoerceValueDelegate untypedCoerceValue = null;
566 CreateDefaultValueDelegate untypedDefaultValueCreator = null;
567 if (validateValue != null)
568 untypedValidateValue = (bindable, value) => validateValue(bindable, (TPropertyType)value);
569 if (propertyChanged != null)
570 untypedBindingPropertyChanged = (bindable, oldValue, newValue) => propertyChanged(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
571 if (propertyChanging != null)
572 untypedBindingPropertyChanging = (bindable, oldValue, newValue) => propertyChanging(bindable, (TPropertyType)oldValue, (TPropertyType)newValue);
573 if (coerceValue != null)
574 untypedCoerceValue = (bindable, value) => coerceValue(bindable, (TPropertyType)value);
575 if (defaultValueCreator != null)
576 untypedDefaultValueCreator = o => defaultValueCreator(o);
578 return new BindableProperty(propertyname, method.ReturnType, typeof(TDeclarer), defaultValue, defaultBindingMode, untypedValidateValue, untypedBindingPropertyChanged, untypedBindingPropertyChanging,
579 untypedCoerceValue, bindingChanging, isReadOnly, untypedDefaultValueCreator);
582 internal static BindableProperty CreateAttached(string propertyName, Type returnType, Type declaringType, object defaultValue, BindingMode defaultBindingMode, ValidateValueDelegate validateValue,
583 BindingPropertyChangedDelegate propertyChanged, BindingPropertyChangingDelegate propertyChanging, CoerceValueDelegate coerceValue, BindablePropertyBindingChanging bindingChanging,
584 bool isReadOnly, CreateDefaultValueDelegate defaultValueCreator = null)
586 return new BindableProperty(propertyName, returnType, declaringType, defaultValue, defaultBindingMode, validateValue, propertyChanged, propertyChanging, coerceValue, bindingChanging, isReadOnly,
587 defaultValueCreator);
590 internal object GetDefaultValue(BindableObject bindable)
592 if (DefaultValueCreator != null)
593 return DefaultValueCreator(bindable);
598 internal bool TryConvert(ref object value)
602 return !ReturnTypeInfo.IsValueType || ReturnTypeInfo.IsGenericType && ReturnTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>);
605 Type valueType = value.GetType();
606 Type type = ReturnType;
608 // Dont support arbitrary IConvertible by limiting which types can use this
609 Type[] convertableTo;
610 TypeConverter typeConverterTo;
611 if (SimpleConvertTypes.TryGetValue(valueType, out convertableTo) && Array.IndexOf(convertableTo, type) != -1)
613 value = Convert.ChangeType(value, type);
615 else if (WellKnownConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
617 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
619 else if (UserCustomConvertTypes.TryGetValue(type, out typeConverterTo) && typeConverterTo.CanConvertFrom(valueType))
621 //Modification for NUI XAML : user defined converter for DynamicResource can be added
622 value = typeConverterTo.ConvertFromInvariantString(value.ToString());
624 else if (!ReturnTypeInfo.IsAssignableFrom(valueType.GetTypeInfo()))
626 var cast = type.GetImplicitConversionOperator(fromType: valueType, toType: type)
627 ?? valueType.GetImplicitConversionOperator(fromType: valueType, toType: type);
632 value = cast.Invoke(null, new[] { value });
638 internal delegate void BindablePropertyBindingChanging(BindableObject bindable, BindingBase oldValue, BindingBase newValue);