Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / Data / DefaultValueConverter.cs / 1 / DefaultValueConverter.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Provide default conversion between source values and // target values, for data binding. The default ValueConverter // typically wraps a type converter. // //--------------------------------------------------------------------------- using System; using System.Globalization; using System.Collections; using System.ComponentModel; using System.Reflection; using System.Windows; using System.Windows.Data; using System.Windows.Navigation; // BaseUriHelper using System.Windows.Markup; // IUriContext using MS.Internal; // Invariant.Assert using System.Diagnostics; namespace MS.Internal.Data { #region DefaultValueConverter internal class DefaultValueConverter { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- protected DefaultValueConverter(TypeConverter typeConverter, Type sourceType, Type targetType, bool shouldConvertFrom, bool shouldConvertTo, DataBindEngine engine) { _typeConverter = typeConverter; _sourceType = sourceType; _targetType = targetType; _shouldConvertFrom = shouldConvertFrom; _shouldConvertTo = shouldConvertTo; _engine = engine; } //------------------------------------------------------ // // Internal static API // //----------------------------------------------------- // static constructor - returns a ValueConverter suitable for converting between // the source and target. The flag indicates whether targetToSource // conversions are actually needed. // if no Converter is needed, return DefaultValueConverter.ValueConverterNotNeeded marker. // if unable to create a DefaultValueConverter, return null to indicate error. internal static IValueConverter Create(Type sourceType, Type targetType, bool targetToSource, DataBindEngine engine) { TypeConverter typeConverter; Type innerType; bool canConvertTo, canConvertFrom; bool sourceIsNullable = false; bool targetIsNullable = false; // sometimes, no conversion is necessary if (sourceType == targetType || (!targetToSource && targetType.IsAssignableFrom(sourceType))) { return ValueConverterNotNeeded; } // the type convert for System.Object is useless. It claims it can // convert from string, but then throws an exception when asked to do // so. So we work around it. if (targetType == typeof(object)) { // The sourceType here might be a Nullable type: consider using // NullableConverter when appropriate. (uncomment following lines) //Type innerType = Nullable.GetUnderlyingType(sourceType); //if (innerType != null) //{ // return new NullableConverter(new ObjectTargetConverter(innerType), // innerType, targetType, true, false); //} // return new ObjectTargetConverter(sourceType, engine); } else if (sourceType == typeof(object)) { // The targetType here might be a Nullable type: consider using // NullableConverter when appropriate. (uncomment following lines) //Type innerType = Nullable.GetUnderlyingType(targetType); // if (innerType != null) // { // return new NullableConverter(new ObjectSourceConverter(innerType), // sourceType, innerType, false, true); // } // return new ObjectSourceConverter(targetType, engine); } // use System.Convert for well-known base types if (SystemConvertConverter.CanConvert(sourceType, targetType)) { return new SystemConvertConverter(sourceType, targetType); } // Need to check for nullable types first, since NullableConverter is a bit over-eager; // TypeConverter for Nullable can convert e.g. Nullableto string // but it ends up doing a different conversion than the TypeConverter for the // generic's inner type, e.g. bug 1361977 innerType = Nullable.GetUnderlyingType(sourceType); if (innerType != null) { sourceType = innerType; sourceIsNullable = true; } innerType = Nullable.GetUnderlyingType(targetType); if (innerType != null) { targetType = innerType; targetIsNullable = true; } if (sourceIsNullable || targetIsNullable) { // single-level recursive call to try to find a converter for basic value types return Create(sourceType, targetType, targetToSource, engine); } // special case for converting IListSource to IList if (typeof(IListSource).IsAssignableFrom(sourceType) && targetType.IsAssignableFrom(typeof(IList))) { return new ListSourceConverter(); } // Interfaces are best handled on a per-instance basis. The type may // not implement the interface, but an instance of a derived type may. if (sourceType.IsInterface || targetType.IsInterface) { return new InterfaceConverter(sourceType, targetType); } // try using the source's type converter typeConverter = GetConverter(sourceType); canConvertTo = (typeConverter != null) ? typeConverter.CanConvertTo(targetType) : false; canConvertFrom = (typeConverter != null) ? typeConverter.CanConvertFrom(targetType) : false; if ((canConvertTo || targetType.IsAssignableFrom(sourceType)) && (!targetToSource || canConvertFrom || sourceType.IsAssignableFrom(targetType))) { return new SourceDefaultValueConverter(typeConverter, sourceType, targetType, targetToSource && canConvertFrom, canConvertTo, engine); } // if that doesn't work, try using the target's type converter typeConverter = GetConverter(targetType); canConvertTo = (typeConverter != null) ? typeConverter.CanConvertTo(sourceType) : false; canConvertFrom = (typeConverter != null) ? typeConverter.CanConvertFrom(sourceType) : false; if ((canConvertFrom || targetType.IsAssignableFrom(sourceType)) && (!targetToSource || canConvertTo || sourceType.IsAssignableFrom(targetType))) { return new TargetDefaultValueConverter(typeConverter, sourceType, targetType, canConvertFrom, targetToSource && canConvertTo, engine); } // nothing worked, give up return null; } internal static TypeConverter GetConverter(Type type) { TypeConverter typeConverter = BamlMapTable.GetKnownConverterFromType_NoCache(type); if (typeConverter == null) { typeConverter = TypeDescriptor.GetConverter(type); } return typeConverter; } // some types have Parse methods that are more successful than their // type converters at converting strings. // [This code is lifted from WinForms - formatter.cs] internal static object TryParse(object o, Type targetType, CultureInfo culture) { object result = DependencyProperty.UnsetValue; string stringValue = o as String; if (stringValue != null) { try { MethodInfo mi; if (culture != null && (mi = targetType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] {StringType, typeof(System.Globalization.NumberStyles), typeof(System.IFormatProvider)}, null)) != null) { result = mi.Invoke(null, new object [] {stringValue, NumberStyles.Any, culture}); } else if (culture != null && (mi = targetType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] {StringType, typeof(System.IFormatProvider)}, null)) != null) { result = mi.Invoke(null, new object [] {stringValue, culture}); } else if ((mi = targetType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] {StringType}, null)) != null) { result = mi.Invoke(null, new object [] {stringValue}); } } catch (TargetInvocationException) { } } return result; } internal static readonly IValueConverter ValueConverterNotNeeded = new ObjectTargetConverter(typeof(object), null); //------------------------------------------------------ // // Protected API // //------------------------------------------------------ protected object ConvertFrom(object o, Type destinationType, DependencyObject targetElement, CultureInfo culture) { return ConvertHelper(o, destinationType, targetElement, culture, false); } protected object ConvertTo(object o, Type destinationType, DependencyObject targetElement, CultureInfo culture) { return ConvertHelper(o, destinationType, targetElement, culture, true); } // for lazy creation of the type converter, since GetConverter is expensive protected void EnsureConverter(Type type) { if (_typeConverter == null) { _typeConverter = GetConverter(type); } } //----------------------------------------------------- // // Private API // //------------------------------------------------------ private object ConvertHelper(object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, bool isForward) { object value = DependencyProperty.UnsetValue; bool needAssignment = (isForward ? !_shouldConvertTo : !_shouldConvertFrom); NotSupportedException savedEx = null; if (!needAssignment) { value = TryParse(o, destinationType, culture); if (value == DependencyProperty.UnsetValue) { // CAUTION: normal value- and type converters are expected to be stateless // and are not allowed to know the target element etc. // The passed in targetElement value must only be used by the ValueConverterContext and // without causing modifications on the target element. // Use extra care to avoid binding engine recursions when accessing any DPs on the targetElement. ValueConverterContext ctx = Engine.ValueConverterContext; try { ctx.SetTargetElement(targetElement); if (isForward) { value = _typeConverter.ConvertTo(ctx, culture, o, destinationType); } else { value = _typeConverter.ConvertFrom(ctx, culture, o); } } catch (NotSupportedException ex) { needAssignment = true; savedEx = ex; } finally { ctx.SetTargetElement(null); } } } if (needAssignment && ( (o != null && destinationType.IsAssignableFrom(o.GetType())) || (o == null && !destinationType.IsValueType) )) { value = o; needAssignment = false; } if (TraceData.IsEnabled) { if ((culture != null) && (savedEx != null)) { TraceData.Trace(TraceEventType.Error, TraceData.DefaultValueConverterFailedForCulture( AvTrace.ToStringHelper(o), AvTrace.TypeName(o), destinationType.ToString(), culture), savedEx); } else if (needAssignment) { TraceData.Trace(TraceEventType.Error, TraceData.DefaultValueConverterFailed( AvTrace.ToStringHelper(o), AvTrace.TypeName(o), destinationType.ToString()), savedEx); } } if (needAssignment && savedEx != null) throw savedEx; return value; } protected DataBindEngine Engine { get { return _engine; } } protected Type _sourceType; protected Type _targetType; private TypeConverter _typeConverter; private bool _shouldConvertFrom; private bool _shouldConvertTo; private DataBindEngine _engine; static Type StringType = typeof(String); } #endregion DefaultValueConverter #region SourceDefaultValueConverter internal class SourceDefaultValueConverter : DefaultValueConverter, IValueConverter { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- public SourceDefaultValueConverter(TypeConverter typeConverter, Type sourceType, Type targetType, bool shouldConvertFrom, bool shouldConvertTo, DataBindEngine engine) : base(typeConverter, sourceType, targetType, shouldConvertFrom, shouldConvertTo, engine) { } //----------------------------------------------------- // // Interfaces (IValueConverter) // //------------------------------------------------------ public object Convert(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _targetType, parameter as DependencyObject, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return ConvertFrom(o, _sourceType, parameter as DependencyObject, culture); } } #endregion SourceDefaultValueConverter #region TargetDefaultValueConverter internal class TargetDefaultValueConverter : DefaultValueConverter, IValueConverter { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ public TargetDefaultValueConverter(TypeConverter typeConverter, Type sourceType, Type targetType, bool shouldConvertFrom, bool shouldConvertTo, DataBindEngine engine) : base(typeConverter, sourceType, targetType, shouldConvertFrom, shouldConvertTo, engine) { } //------------------------------------------------------ // // Interfaces (IValueConverter) // //----------------------------------------------------- public object Convert(object o, Type type, object parameter, CultureInfo culture) { return ConvertFrom(o, _targetType, parameter as DependencyObject, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _sourceType, parameter as DependencyObject, culture); } } #endregion TargetDefaultValueConverter #region SystemConvertConverter internal class SystemConvertConverter : IValueConverter { public SystemConvertConverter(Type sourceType, Type targetType) { _sourceType = sourceType; _targetType = targetType; } public object Convert(object o, Type type, object parameter, CultureInfo culture) { return System.Convert.ChangeType(o, _targetType, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { object parsedValue = DefaultValueConverter.TryParse(o, _sourceType, culture); return (parsedValue != DependencyProperty.UnsetValue) ? parsedValue : System.Convert.ChangeType(o, _sourceType, culture); } // ASSUMPTION: sourceType != targetType public static bool CanConvert(Type sourceType, Type targetType) { // This assert is not Invariant.Assert because this will not cause // harm; It would just be odd. Debug.Assert(sourceType != targetType); // DateTime can only be converted to and from String type if (sourceType == typeof(DateTime)) return (targetType == typeof(String)); if (targetType == typeof(DateTime)) return (sourceType == typeof(String)); // Char can only be converted to a subset of supported types if (sourceType == typeof(Char)) return CanConvertChar(targetType); if (targetType == typeof(Char)) return CanConvertChar(sourceType); // Using nested loops is up to 40% more efficient than using one loop for (int i = 0; i < SupportedTypes.Length; ++i) { if (sourceType == SupportedTypes[i]) { ++i; // assuming (sourceType != targetType), start at next type for (; i < SupportedTypes.Length; ++i) { if (targetType == SupportedTypes[i]) return true; } } else if (targetType == SupportedTypes[i]) { ++i; // assuming (sourceType != targetType), start at next type for (; i < SupportedTypes.Length; ++i) { if (sourceType == SupportedTypes[i]) return true; } } } return false; } private static bool CanConvertChar(Type type) { for (int i = 0; i < CharSupportedTypes.Length; ++i) { if (type == CharSupportedTypes[i]) return true; } return false; } Type _sourceType, _targetType; // list of types supported by System.Convert (from the SDK) static readonly Type[] SupportedTypes = { typeof(String), // put common types up front typeof(Int32), typeof(Int64), typeof(Single), typeof(Double), typeof(Decimal),typeof(Boolean), typeof(Byte), typeof(Int16), typeof(UInt32), typeof(UInt64), typeof(UInt16), typeof(SByte), // non-CLS compliant types }; // list of types supported by System.Convert for Char Type(from the SDK) static readonly Type[] CharSupportedTypes = { typeof(String), // put common types up front typeof(Int32), typeof(Int64), typeof(Byte), typeof(Int16), typeof(UInt32), typeof(UInt64), typeof(UInt16), typeof(SByte), // non-CLS compliant types }; } #endregion SystemConvertConverter #region ObjectConverter // internal class ObjectTargetConverter : DefaultValueConverter, IValueConverter { //------------------------------------------------------ // // Constructors // //----------------------------------------------------- public ObjectTargetConverter(Type sourceType, DataBindEngine engine) : base(null, sourceType, typeof(object), true /* shouldConvertFrom */, false /* shouldConvertTo */, engine) { } //----------------------------------------------------- // // Interfaces (IValueConverter) // //----------------------------------------------------- public object Convert(object o, Type type, object parameter, CultureInfo culture) { // conversion from any type to object is easy return o; } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { // if types are compatible, just pass the value through if (o == null && !_sourceType.IsValueType) return o; if (o != null && _sourceType.IsAssignableFrom(o.GetType())) return o; // if source type is string, use ToString (string's type converter doesn't // do it for us - boo!) if (_sourceType == typeof(String)) return o.ToString(); // otherwise, use system converter EnsureConverter(_sourceType); return ConvertFrom(o, _sourceType, parameter as DependencyObject, culture); } } // internal class ObjectSourceConverter : DefaultValueConverter, IValueConverter { //------------------------------------------------------ // // Constructors // //----------------------------------------------------- public ObjectSourceConverter(Type targetType, DataBindEngine engine) : base(null, typeof(object), targetType, true /* shouldConvertFrom */, false /* shouldConvertTo */, engine) { } //------------------------------------------------------ // // Interfaces (IValueConverter) // //------------------------------------------------------ public object Convert(object o, Type type, object parameter, CultureInfo culture) { // if types are compatible, just pass the value through if ((o != null && _targetType.IsAssignableFrom(o.GetType())) || (o == null && !_targetType.IsValueType)) return o; // if target type is string, use ToString (string's type converter doesn't // do it for us - boo!) if (_targetType == typeof(String)) return o.ToString(); // otherwise, use system converter EnsureConverter(_targetType); return ConvertFrom(o, _targetType, parameter as DependencyObject, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { // conversion from any type to object is easy return o; } } #endregion ObjectConverter #region ListSourceConverter internal class ListSourceConverter : IValueConverter { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ //----------------------------------------------------- // // Interfaces (IValueConverter) // //----------------------------------------------------- public object Convert(object o, Type type, object parameter, CultureInfo culture) { IList il = null; IListSource ils = o as IListSource; if (ils != null) { il = ils.GetList(); } return il; } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return null; } } #endregion ListSourceConverter #region InterfaceConverter internal class InterfaceConverter : IValueConverter { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ internal InterfaceConverter(Type sourceType, Type targetType) { _sourceType = sourceType; _targetType = targetType; } //----------------------------------------------------- // // Interfaces (IValueConverter) // //------------------------------------------------------ public object Convert(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _targetType); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _sourceType); } private object ConvertTo(object o, Type type) { return type.IsInstanceOfType(o) ? o : null; } Type _sourceType; Type _targetType; } #endregion InterfaceConverter // TypeDescriptor context to provide TypeConverters with the app's BaseUri internal class ValueConverterContext : ITypeDescriptorContext, IUriContext { // redirect to IUriContext service virtual public object GetService(Type serviceType) { if (serviceType == typeof(IUriContext)) { return this as IUriContext; } return null; } // call BaseUriHelper.GetBaseUri() if the target element is known. // It does a tree walk trying to find a IUriContext implementer or a root element which has BaseUri explicitly set // This get_BaseUri is only called from a TypeConverter which in turn // is called from one of our DefaultConverters in this source file. public Uri BaseUri { get { if (_cachedBaseUri == null) { if (_targetElement != null) { // GetBaseUri looks for a optional BaseUriProperty attached DP. // This can cause a re-entrancy if that BaseUri is also data bound. // Ideally the BaseUri DP should be flagged as NotDataBindable but // unfortunately that DP is a core DP and not aware of the framework metadata // // GetBaseUri can raise SecurityExceptions if e.g. the app doesn't have // the correct FileIO permission. // Any security exception is initially caught in BindingExpression.ConvertHelper/.ConvertBackHelper // but then rethrown since it is a critical exception. _cachedBaseUri = BaseUriHelper.GetBaseUri(_targetElement); } else { _cachedBaseUri = BaseUriHelper.BaseUri; } } return _cachedBaseUri; } set { throw new NotSupportedException(); } } internal void SetTargetElement(DependencyObject target) { if (target != null) _nestingLevel++; else { if (_nestingLevel > 0) _nestingLevel--; } Invariant.Assert((_nestingLevel <= 1), "illegal to recurse/reenter ValueConverterContext.SetTargetElement()"); _targetElement = target; _cachedBaseUri = null; } // empty default implementation of interface ITypeDescriptorContext public IContainer Container { get { return null; } } public object Instance { get { return null; } } public PropertyDescriptor PropertyDescriptor { get { return null;} } public void OnComponentChanged() { } public bool OnComponentChanging() { return false; } // fields private DependencyObject _targetElement; private int _nestingLevel; private Uri _cachedBaseUri; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // // // Copyright (C) Microsoft Corporation. All rights reserved. // // // Description: Provide default conversion between source values and // target values, for data binding. The default ValueConverter // typically wraps a type converter. // //--------------------------------------------------------------------------- using System; using System.Globalization; using System.Collections; using System.ComponentModel; using System.Reflection; using System.Windows; using System.Windows.Data; using System.Windows.Navigation; // BaseUriHelper using System.Windows.Markup; // IUriContext using MS.Internal; // Invariant.Assert using System.Diagnostics; namespace MS.Internal.Data { #region DefaultValueConverter internal class DefaultValueConverter { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- protected DefaultValueConverter(TypeConverter typeConverter, Type sourceType, Type targetType, bool shouldConvertFrom, bool shouldConvertTo, DataBindEngine engine) { _typeConverter = typeConverter; _sourceType = sourceType; _targetType = targetType; _shouldConvertFrom = shouldConvertFrom; _shouldConvertTo = shouldConvertTo; _engine = engine; } //------------------------------------------------------ // // Internal static API // //----------------------------------------------------- // static constructor - returns a ValueConverter suitable for converting between // the source and target. The flag indicates whether targetToSource // conversions are actually needed. // if no Converter is needed, return DefaultValueConverter.ValueConverterNotNeeded marker. // if unable to create a DefaultValueConverter, return null to indicate error. internal static IValueConverter Create(Type sourceType, Type targetType, bool targetToSource, DataBindEngine engine) { TypeConverter typeConverter; Type innerType; bool canConvertTo, canConvertFrom; bool sourceIsNullable = false; bool targetIsNullable = false; // sometimes, no conversion is necessary if (sourceType == targetType || (!targetToSource && targetType.IsAssignableFrom(sourceType))) { return ValueConverterNotNeeded; } // the type convert for System.Object is useless. It claims it can // convert from string, but then throws an exception when asked to do // so. So we work around it. if (targetType == typeof(object)) { // The sourceType here might be a Nullable type: consider using // NullableConverter when appropriate. (uncomment following lines) //Type innerType = Nullable.GetUnderlyingType(sourceType); //if (innerType != null) //{ // return new NullableConverter(new ObjectTargetConverter(innerType), // innerType, targetType, true, false); //} // return new ObjectTargetConverter(sourceType, engine); } else if (sourceType == typeof(object)) { // The targetType here might be a Nullable type: consider using // NullableConverter when appropriate. (uncomment following lines) //Type innerType = Nullable.GetUnderlyingType(targetType); // if (innerType != null) // { // return new NullableConverter(new ObjectSourceConverter(innerType), // sourceType, innerType, false, true); // } // return new ObjectSourceConverter(targetType, engine); } // use System.Convert for well-known base types if (SystemConvertConverter.CanConvert(sourceType, targetType)) { return new SystemConvertConverter(sourceType, targetType); } // Need to check for nullable types first, since NullableConverter is a bit over-eager; // TypeConverter for Nullable can convert e.g. Nullableto string // but it ends up doing a different conversion than the TypeConverter for the // generic's inner type, e.g. bug 1361977 innerType = Nullable.GetUnderlyingType(sourceType); if (innerType != null) { sourceType = innerType; sourceIsNullable = true; } innerType = Nullable.GetUnderlyingType(targetType); if (innerType != null) { targetType = innerType; targetIsNullable = true; } if (sourceIsNullable || targetIsNullable) { // single-level recursive call to try to find a converter for basic value types return Create(sourceType, targetType, targetToSource, engine); } // special case for converting IListSource to IList if (typeof(IListSource).IsAssignableFrom(sourceType) && targetType.IsAssignableFrom(typeof(IList))) { return new ListSourceConverter(); } // Interfaces are best handled on a per-instance basis. The type may // not implement the interface, but an instance of a derived type may. if (sourceType.IsInterface || targetType.IsInterface) { return new InterfaceConverter(sourceType, targetType); } // try using the source's type converter typeConverter = GetConverter(sourceType); canConvertTo = (typeConverter != null) ? typeConverter.CanConvertTo(targetType) : false; canConvertFrom = (typeConverter != null) ? typeConverter.CanConvertFrom(targetType) : false; if ((canConvertTo || targetType.IsAssignableFrom(sourceType)) && (!targetToSource || canConvertFrom || sourceType.IsAssignableFrom(targetType))) { return new SourceDefaultValueConverter(typeConverter, sourceType, targetType, targetToSource && canConvertFrom, canConvertTo, engine); } // if that doesn't work, try using the target's type converter typeConverter = GetConverter(targetType); canConvertTo = (typeConverter != null) ? typeConverter.CanConvertTo(sourceType) : false; canConvertFrom = (typeConverter != null) ? typeConverter.CanConvertFrom(sourceType) : false; if ((canConvertFrom || targetType.IsAssignableFrom(sourceType)) && (!targetToSource || canConvertTo || sourceType.IsAssignableFrom(targetType))) { return new TargetDefaultValueConverter(typeConverter, sourceType, targetType, canConvertFrom, targetToSource && canConvertTo, engine); } // nothing worked, give up return null; } internal static TypeConverter GetConverter(Type type) { TypeConverter typeConverter = BamlMapTable.GetKnownConverterFromType_NoCache(type); if (typeConverter == null) { typeConverter = TypeDescriptor.GetConverter(type); } return typeConverter; } // some types have Parse methods that are more successful than their // type converters at converting strings. // [This code is lifted from WinForms - formatter.cs] internal static object TryParse(object o, Type targetType, CultureInfo culture) { object result = DependencyProperty.UnsetValue; string stringValue = o as String; if (stringValue != null) { try { MethodInfo mi; if (culture != null && (mi = targetType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] {StringType, typeof(System.Globalization.NumberStyles), typeof(System.IFormatProvider)}, null)) != null) { result = mi.Invoke(null, new object [] {stringValue, NumberStyles.Any, culture}); } else if (culture != null && (mi = targetType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] {StringType, typeof(System.IFormatProvider)}, null)) != null) { result = mi.Invoke(null, new object [] {stringValue, culture}); } else if ((mi = targetType.GetMethod("Parse", BindingFlags.Public | BindingFlags.Static, null, new Type[] {StringType}, null)) != null) { result = mi.Invoke(null, new object [] {stringValue}); } } catch (TargetInvocationException) { } } return result; } internal static readonly IValueConverter ValueConverterNotNeeded = new ObjectTargetConverter(typeof(object), null); //------------------------------------------------------ // // Protected API // //------------------------------------------------------ protected object ConvertFrom(object o, Type destinationType, DependencyObject targetElement, CultureInfo culture) { return ConvertHelper(o, destinationType, targetElement, culture, false); } protected object ConvertTo(object o, Type destinationType, DependencyObject targetElement, CultureInfo culture) { return ConvertHelper(o, destinationType, targetElement, culture, true); } // for lazy creation of the type converter, since GetConverter is expensive protected void EnsureConverter(Type type) { if (_typeConverter == null) { _typeConverter = GetConverter(type); } } //----------------------------------------------------- // // Private API // //------------------------------------------------------ private object ConvertHelper(object o, Type destinationType, DependencyObject targetElement, CultureInfo culture, bool isForward) { object value = DependencyProperty.UnsetValue; bool needAssignment = (isForward ? !_shouldConvertTo : !_shouldConvertFrom); NotSupportedException savedEx = null; if (!needAssignment) { value = TryParse(o, destinationType, culture); if (value == DependencyProperty.UnsetValue) { // CAUTION: normal value- and type converters are expected to be stateless // and are not allowed to know the target element etc. // The passed in targetElement value must only be used by the ValueConverterContext and // without causing modifications on the target element. // Use extra care to avoid binding engine recursions when accessing any DPs on the targetElement. ValueConverterContext ctx = Engine.ValueConverterContext; try { ctx.SetTargetElement(targetElement); if (isForward) { value = _typeConverter.ConvertTo(ctx, culture, o, destinationType); } else { value = _typeConverter.ConvertFrom(ctx, culture, o); } } catch (NotSupportedException ex) { needAssignment = true; savedEx = ex; } finally { ctx.SetTargetElement(null); } } } if (needAssignment && ( (o != null && destinationType.IsAssignableFrom(o.GetType())) || (o == null && !destinationType.IsValueType) )) { value = o; needAssignment = false; } if (TraceData.IsEnabled) { if ((culture != null) && (savedEx != null)) { TraceData.Trace(TraceEventType.Error, TraceData.DefaultValueConverterFailedForCulture( AvTrace.ToStringHelper(o), AvTrace.TypeName(o), destinationType.ToString(), culture), savedEx); } else if (needAssignment) { TraceData.Trace(TraceEventType.Error, TraceData.DefaultValueConverterFailed( AvTrace.ToStringHelper(o), AvTrace.TypeName(o), destinationType.ToString()), savedEx); } } if (needAssignment && savedEx != null) throw savedEx; return value; } protected DataBindEngine Engine { get { return _engine; } } protected Type _sourceType; protected Type _targetType; private TypeConverter _typeConverter; private bool _shouldConvertFrom; private bool _shouldConvertTo; private DataBindEngine _engine; static Type StringType = typeof(String); } #endregion DefaultValueConverter #region SourceDefaultValueConverter internal class SourceDefaultValueConverter : DefaultValueConverter, IValueConverter { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- public SourceDefaultValueConverter(TypeConverter typeConverter, Type sourceType, Type targetType, bool shouldConvertFrom, bool shouldConvertTo, DataBindEngine engine) : base(typeConverter, sourceType, targetType, shouldConvertFrom, shouldConvertTo, engine) { } //----------------------------------------------------- // // Interfaces (IValueConverter) // //------------------------------------------------------ public object Convert(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _targetType, parameter as DependencyObject, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return ConvertFrom(o, _sourceType, parameter as DependencyObject, culture); } } #endregion SourceDefaultValueConverter #region TargetDefaultValueConverter internal class TargetDefaultValueConverter : DefaultValueConverter, IValueConverter { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ public TargetDefaultValueConverter(TypeConverter typeConverter, Type sourceType, Type targetType, bool shouldConvertFrom, bool shouldConvertTo, DataBindEngine engine) : base(typeConverter, sourceType, targetType, shouldConvertFrom, shouldConvertTo, engine) { } //------------------------------------------------------ // // Interfaces (IValueConverter) // //----------------------------------------------------- public object Convert(object o, Type type, object parameter, CultureInfo culture) { return ConvertFrom(o, _targetType, parameter as DependencyObject, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _sourceType, parameter as DependencyObject, culture); } } #endregion TargetDefaultValueConverter #region SystemConvertConverter internal class SystemConvertConverter : IValueConverter { public SystemConvertConverter(Type sourceType, Type targetType) { _sourceType = sourceType; _targetType = targetType; } public object Convert(object o, Type type, object parameter, CultureInfo culture) { return System.Convert.ChangeType(o, _targetType, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { object parsedValue = DefaultValueConverter.TryParse(o, _sourceType, culture); return (parsedValue != DependencyProperty.UnsetValue) ? parsedValue : System.Convert.ChangeType(o, _sourceType, culture); } // ASSUMPTION: sourceType != targetType public static bool CanConvert(Type sourceType, Type targetType) { // This assert is not Invariant.Assert because this will not cause // harm; It would just be odd. Debug.Assert(sourceType != targetType); // DateTime can only be converted to and from String type if (sourceType == typeof(DateTime)) return (targetType == typeof(String)); if (targetType == typeof(DateTime)) return (sourceType == typeof(String)); // Char can only be converted to a subset of supported types if (sourceType == typeof(Char)) return CanConvertChar(targetType); if (targetType == typeof(Char)) return CanConvertChar(sourceType); // Using nested loops is up to 40% more efficient than using one loop for (int i = 0; i < SupportedTypes.Length; ++i) { if (sourceType == SupportedTypes[i]) { ++i; // assuming (sourceType != targetType), start at next type for (; i < SupportedTypes.Length; ++i) { if (targetType == SupportedTypes[i]) return true; } } else if (targetType == SupportedTypes[i]) { ++i; // assuming (sourceType != targetType), start at next type for (; i < SupportedTypes.Length; ++i) { if (sourceType == SupportedTypes[i]) return true; } } } return false; } private static bool CanConvertChar(Type type) { for (int i = 0; i < CharSupportedTypes.Length; ++i) { if (type == CharSupportedTypes[i]) return true; } return false; } Type _sourceType, _targetType; // list of types supported by System.Convert (from the SDK) static readonly Type[] SupportedTypes = { typeof(String), // put common types up front typeof(Int32), typeof(Int64), typeof(Single), typeof(Double), typeof(Decimal),typeof(Boolean), typeof(Byte), typeof(Int16), typeof(UInt32), typeof(UInt64), typeof(UInt16), typeof(SByte), // non-CLS compliant types }; // list of types supported by System.Convert for Char Type(from the SDK) static readonly Type[] CharSupportedTypes = { typeof(String), // put common types up front typeof(Int32), typeof(Int64), typeof(Byte), typeof(Int16), typeof(UInt32), typeof(UInt64), typeof(UInt16), typeof(SByte), // non-CLS compliant types }; } #endregion SystemConvertConverter #region ObjectConverter // internal class ObjectTargetConverter : DefaultValueConverter, IValueConverter { //------------------------------------------------------ // // Constructors // //----------------------------------------------------- public ObjectTargetConverter(Type sourceType, DataBindEngine engine) : base(null, sourceType, typeof(object), true /* shouldConvertFrom */, false /* shouldConvertTo */, engine) { } //----------------------------------------------------- // // Interfaces (IValueConverter) // //----------------------------------------------------- public object Convert(object o, Type type, object parameter, CultureInfo culture) { // conversion from any type to object is easy return o; } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { // if types are compatible, just pass the value through if (o == null && !_sourceType.IsValueType) return o; if (o != null && _sourceType.IsAssignableFrom(o.GetType())) return o; // if source type is string, use ToString (string's type converter doesn't // do it for us - boo!) if (_sourceType == typeof(String)) return o.ToString(); // otherwise, use system converter EnsureConverter(_sourceType); return ConvertFrom(o, _sourceType, parameter as DependencyObject, culture); } } // internal class ObjectSourceConverter : DefaultValueConverter, IValueConverter { //------------------------------------------------------ // // Constructors // //----------------------------------------------------- public ObjectSourceConverter(Type targetType, DataBindEngine engine) : base(null, typeof(object), targetType, true /* shouldConvertFrom */, false /* shouldConvertTo */, engine) { } //------------------------------------------------------ // // Interfaces (IValueConverter) // //------------------------------------------------------ public object Convert(object o, Type type, object parameter, CultureInfo culture) { // if types are compatible, just pass the value through if ((o != null && _targetType.IsAssignableFrom(o.GetType())) || (o == null && !_targetType.IsValueType)) return o; // if target type is string, use ToString (string's type converter doesn't // do it for us - boo!) if (_targetType == typeof(String)) return o.ToString(); // otherwise, use system converter EnsureConverter(_targetType); return ConvertFrom(o, _targetType, parameter as DependencyObject, culture); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { // conversion from any type to object is easy return o; } } #endregion ObjectConverter #region ListSourceConverter internal class ListSourceConverter : IValueConverter { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ //----------------------------------------------------- // // Interfaces (IValueConverter) // //----------------------------------------------------- public object Convert(object o, Type type, object parameter, CultureInfo culture) { IList il = null; IListSource ils = o as IListSource; if (ils != null) { il = ils.GetList(); } return il; } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return null; } } #endregion ListSourceConverter #region InterfaceConverter internal class InterfaceConverter : IValueConverter { //----------------------------------------------------- // // Constructors // //------------------------------------------------------ internal InterfaceConverter(Type sourceType, Type targetType) { _sourceType = sourceType; _targetType = targetType; } //----------------------------------------------------- // // Interfaces (IValueConverter) // //------------------------------------------------------ public object Convert(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _targetType); } public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) { return ConvertTo(o, _sourceType); } private object ConvertTo(object o, Type type) { return type.IsInstanceOfType(o) ? o : null; } Type _sourceType; Type _targetType; } #endregion InterfaceConverter // TypeDescriptor context to provide TypeConverters with the app's BaseUri internal class ValueConverterContext : ITypeDescriptorContext, IUriContext { // redirect to IUriContext service virtual public object GetService(Type serviceType) { if (serviceType == typeof(IUriContext)) { return this as IUriContext; } return null; } // call BaseUriHelper.GetBaseUri() if the target element is known. // It does a tree walk trying to find a IUriContext implementer or a root element which has BaseUri explicitly set // This get_BaseUri is only called from a TypeConverter which in turn // is called from one of our DefaultConverters in this source file. public Uri BaseUri { get { if (_cachedBaseUri == null) { if (_targetElement != null) { // GetBaseUri looks for a optional BaseUriProperty attached DP. // This can cause a re-entrancy if that BaseUri is also data bound. // Ideally the BaseUri DP should be flagged as NotDataBindable but // unfortunately that DP is a core DP and not aware of the framework metadata // // GetBaseUri can raise SecurityExceptions if e.g. the app doesn't have // the correct FileIO permission. // Any security exception is initially caught in BindingExpression.ConvertHelper/.ConvertBackHelper // but then rethrown since it is a critical exception. _cachedBaseUri = BaseUriHelper.GetBaseUri(_targetElement); } else { _cachedBaseUri = BaseUriHelper.BaseUri; } } return _cachedBaseUri; } set { throw new NotSupportedException(); } } internal void SetTargetElement(DependencyObject target) { if (target != null) _nestingLevel++; else { if (_nestingLevel > 0) _nestingLevel--; } Invariant.Assert((_nestingLevel <= 1), "illegal to recurse/reenter ValueConverterContext.SetTargetElement()"); _targetElement = target; _cachedBaseUri = null; } // empty default implementation of interface ITypeDescriptorContext public IContainer Container { get { return null; } } public object Instance { get { return null; } } public PropertyDescriptor PropertyDescriptor { get { return null;} } public void OnComponentChanged() { } public bool OnComponentChanging() { return false; } // fields private DependencyObject _targetElement; private int _nestingLevel; private Uri _cachedBaseUri; } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MessageSmuggler.cs
- TextBox.cs
- ClusterRegistryConfigurationProvider.cs
- TreeViewBindingsEditor.cs
- ViewLoader.cs
- SchemaReference.cs
- SqlDataSourceStatusEventArgs.cs
- SqlDataSourceCommandEventArgs.cs
- ReservationNotFoundException.cs
- Byte.cs
- CompilerLocalReference.cs
- DataListItem.cs
- CollectionChangeEventArgs.cs
- WorkflowApplicationException.cs
- HttpListenerContext.cs
- EventArgs.cs
- XmlSchemaComplexContentRestriction.cs
- AnnotationDocumentPaginator.cs
- __ComObject.cs
- ColorConverter.cs
- NavigationFailedEventArgs.cs
- ProfileSettings.cs
- Nodes.cs
- StringReader.cs
- XmlDataSource.cs
- BamlRecords.cs
- ExpressionBuilderCollection.cs
- Keyboard.cs
- NativeActivityContext.cs
- DataRowView.cs
- TransformerConfigurationWizardBase.cs
- PipelineModuleStepContainer.cs
- DataFieldConverter.cs
- Point4D.cs
- ImageSource.cs
- ReflectPropertyDescriptor.cs
- HtmlAnchor.cs
- FormsAuthenticationTicket.cs
- TemplatingOptionsDialog.cs
- documentsequencetextview.cs
- RefreshPropertiesAttribute.cs
- TimeoutValidationAttribute.cs
- RSAOAEPKeyExchangeDeformatter.cs
- LookupBindingPropertiesAttribute.cs
- XamlToRtfWriter.cs
- StructuredProperty.cs
- StyleBamlTreeBuilder.cs
- MouseGesture.cs
- Matrix.cs
- Char.cs
- Message.cs
- Debug.cs
- TextElementEditingBehaviorAttribute.cs
- DefaultEvaluationContext.cs
- SaveWorkflowCommand.cs
- BooleanExpr.cs
- CompositeDuplexBindingElementImporter.cs
- Automation.cs
- TraceInternal.cs
- PackWebRequestFactory.cs
- SourceInterpreter.cs
- ComplexBindingPropertiesAttribute.cs
- TimeZone.cs
- odbcmetadatafactory.cs
- DockingAttribute.cs
- ObjectTag.cs
- UIElementParaClient.cs
- OrderedDictionary.cs
- EditModeSwitchButton.cs
- WebPartHelpVerb.cs
- TokenBasedSet.cs
- ListViewCancelEventArgs.cs
- DispatcherTimer.cs
- SoapFault.cs
- SettingsPropertyValueCollection.cs
- CoreSwitches.cs
- Graph.cs
- EnvironmentPermission.cs
- SecureUICommand.cs
- Page.cs
- TaskExceptionHolder.cs
- LongCountAggregationOperator.cs
- Globals.cs
- CollectionChangedEventManager.cs
- SafeFreeMibTable.cs
- WebPartMinimizeVerb.cs
- unitconverter.cs
- ChineseLunisolarCalendar.cs
- HotSpotCollection.cs
- ExpressionPrefixAttribute.cs
- DispatchChannelSink.cs
- DbgCompiler.cs
- PrimitiveCodeDomSerializer.cs
- COM2IVsPerPropertyBrowsingHandler.cs
- PrimitiveDataContract.cs
- TcpSocketManager.cs
- UIElementParagraph.cs
- ContentType.cs
- infer.cs
- DocumentPageTextView.cs