DefaultValueConverter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / 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. Nullable to 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. Nullable to 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

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK