/// <summary> /// This method is used to check whether the value is Valid if needed. /// </summary> /// <param name="initialValue"></param> internal void CheckInitialValueValidity(object initialValue) { if (ParentBinding.ValidatesOnExceptions && ParentBinding.ValidatesOnLoad) { if (!PropertyPathWalker.IsPathBroken) { INTERNAL_ForceValidateOnNextSetValue = false; try { PropertyPathNode node = (PropertyPathNode)PropertyPathWalker.FinalNode; node.SetValue(node.Value); //we set the source property to its own value to check whether it causes an exception, in which case the value is not valid. } catch (Exception e) //todo: put the content of this catch in a method which will be called here and in UpdateSourceObject (OR put the whole try/catch in the method and put the Value to set as parameter). { //We get the new Error (which is the innermost exception as far as I know): Exception currentException = e; if (Interop.IsRunningInTheSimulator) // Note: "InnerException" is only supported in the Simulator as of July 27, 2017. { while (currentException.InnerException != null) { currentException = currentException.InnerException; } } Validation.MarkInvalid(this, new ValidationError(this) { Exception = currentException, ErrorContent = currentException.Message }); } } } }
internal void UpdateSourceObject(object value) { if (!PropertyPathWalker.IsPathBroken) { PropertyPathNode node = (PropertyPathNode)PropertyPathWalker.FinalNode; bool oldIsUpdating = IsUpdating; try { Type expectedType = null; object convertedValue = value; if (ParentBinding.Converter != null) { if (node.DependencyProperty != null) { #if MIGRATION convertedValue = ParentBinding.Converter.ConvertBack(value, node.DependencyProperty.PropertyType, ParentBinding.ConverterParameter, ParentBinding.ConverterCulture); #else convertedValue = ParentBinding.Converter.ConvertBack(value, node.DependencyProperty.PropertyType, ParentBinding.ConverterParameter, ParentBinding.ConverterLanguage); #endif expectedType = node.DependencyProperty.PropertyType; } else if (node.PropertyInfo != null) { #if MIGRATION convertedValue = ParentBinding.Converter.ConvertBack(value, node.PropertyInfo.PropertyType, ParentBinding.ConverterParameter, ParentBinding.ConverterCulture); #else convertedValue = ParentBinding.Converter.ConvertBack(value, node.PropertyInfo.PropertyType, ParentBinding.ConverterParameter, ParentBinding.ConverterLanguage); #endif expectedType = node.PropertyInfo.PropertyType; } else if (node.FieldInfo != null) { #if MIGRATION convertedValue = ParentBinding.Converter.ConvertBack(value, node.FieldInfo.FieldType, ParentBinding.ConverterParameter, ParentBinding.ConverterCulture); #else convertedValue = ParentBinding.Converter.ConvertBack(value, node.FieldInfo.FieldType, ParentBinding.ConverterParameter, ParentBinding.ConverterLanguage); #endif expectedType = node.FieldInfo.FieldType; } } else //we only need to set expectedType: { if (node.DependencyProperty != null) { expectedType = node.DependencyProperty.PropertyType; } else if (node.PropertyInfo != null) { expectedType = node.PropertyInfo.PropertyType; } else if (node.FieldInfo != null) { expectedType = node.FieldInfo.FieldType; } } bool typeAcceptsNullAsValue = !expectedType.IsValueType || expectedType.FullName.StartsWith("System.Nullable`1"); bool isNotNullOrIsNullAccepted = ((convertedValue != null) || typeAcceptsNullAsValue); if (isNotNullOrIsNullAccepted) //Note: we put this test here to avoid making unneccessary tests but the point is that the new value is simply ignored since it doesn't fit the property (cannot set a non-nullable property to null). { //bool oldIsUpdating = IsUpdating; IsUpdating = true; Type[] AutoConvertTypes = { typeof(Int16), typeof(Int32), typeof(Int64), typeof(Double), typeof(Uri) }; bool typeFound = false; if ((AutoConvertTypes.Contains(expectedType)) && convertedValue is string) //todo: find a way to do this more efficiently (and maybe mode generic ?) { typeFound = true; if (expectedType == typeof(Int16)) { convertedValue = Int16.Parse((string)convertedValue); } else if (expectedType == typeof(Int32)) { convertedValue = Int32.Parse((string)convertedValue); } else if (expectedType == typeof(Int64)) { convertedValue = Int64.Parse((string)convertedValue); } else if (expectedType == typeof(Double)) { convertedValue = Double.Parse((string)convertedValue); } else if (expectedType == typeof(Uri)) { convertedValue = new Uri((string)convertedValue); } } //todo: partially merge this "if" and the previous one. if ((!typeFound && TypeFromStringConverters.CanTypeBeConverted(expectedType)) && convertedValue is string) { typeFound = true; convertedValue = TypeFromStringConverters.ConvertFromInvariantString(expectedType, (string)convertedValue); } if (!typeFound && convertedValue != null && (expectedType == typeof(string))) { convertedValue = convertedValue.ToString(); } node.SetValue(convertedValue); Validation.ClearInvalid(this); } } catch (Exception e) { //If we have ValidatesOnExceptions set to true, we display a popup with the error close to the element. if (ParentBinding.ValidatesOnExceptions) { //We get the new Error (which is the innermost exception as far as I know): Exception currentException = e; if (Interop.IsRunningInTheSimulator) // Note: "InnerException" is only supported in the Simulator as of July 27, 2017. { while (currentException.InnerException != null) { currentException = currentException.InnerException; } } Validation.MarkInvalid(this, new ValidationError(this) { Exception = currentException, ErrorContent = currentException.Message }); } } finally { IsUpdating = oldIsUpdating; } } }