File: src\Framework\System\Windows\Controls\VirtualizationCacheLengthConverter.cs
Project: wpf\PresentationFramework.csproj (PresentationFramework)
//---------------------------------------------------------------------------
//
// <copyright file="VirtualizationCacheLength.cs" company="Microsoft">
//    Copyright (C) Microsoft Corporation.  All rights reserved.
// </copyright>
//
// Description: Virtualization cache length converter implementation
//
//---------------------------------------------------------------------------
 
using MS.Internal;
using MS.Utility;
using System.ComponentModel;
using System.Windows;
using System;
using System.Security;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Windows.Markup;
using System.Text;
 
namespace System.Windows.Controls
{
    /// <summary>
    /// VirtualizationCacheLengthConverter - Converter class for converting
    /// instances of other types to and from VirtualizationCacheLength instances.
    /// </summary>
    public class VirtualizationCacheLengthConverter : TypeConverter
    {
        #region Public Methods
 
        /// <summary>
        /// CanConvertFrom - Returns whether or not this class can convert from a given type.
        /// </summary>
        /// <returns>
        /// bool - True if thie converter can convert from the provided type, false if not.
        /// </returns>
        /// <param name="typeDescriptorContext"> The ITypeDescriptorContext for this call. </param>
        /// <param name="sourceType"> The Type being queried for support. </param>
        public override bool CanConvertFrom(ITypeDescriptorContext typeDescriptorContext, Type sourceType)
        {
            // We can only handle strings, integral and floating types
            TypeCode tc = Type.GetTypeCode(sourceType);
            switch (tc)
            {
                case TypeCode.String:
                case TypeCode.Decimal:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.UInt16:
                case TypeCode.UInt32:
                case TypeCode.UInt64:
                    return true;
 
                default:
                    return false;
            }
        }
 
        /// <summary>
        /// CanConvertTo - Returns whether or not this class can convert to a given type.
        /// </summary>
        /// <returns>
        /// bool - True if this converter can convert to the provided type, false if not.
        /// </returns>
        /// <param name="typeDescriptorContext"> The ITypeDescriptorContext for this call. </param>
        /// <param name="destinationType"> The Type being queried for support. </param>
        public override bool CanConvertTo(ITypeDescriptorContext typeDescriptorContext, Type destinationType)
        {
            // We can convert to an InstanceDescriptor or to a string.
            if (    destinationType == typeof(InstanceDescriptor)
                ||  destinationType == typeof(string))
            {
                return true;
            }
            else
            {
                return false;
            }
        }
 
        /// <summary>
        /// ConvertFrom - Attempt to convert to a VirtualizationCacheLength from the given object
        /// </summary>
        /// <returns>
        /// The VirtualizationCacheLength which was constructed.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// An ArgumentNullException is thrown if the example object is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// An ArgumentException is thrown if the example object is not null and is not a valid type
        /// which can be converted to a VirtualizationCacheLength.
        /// </exception>
        /// <param name="typeDescriptorContext"> The ITypeDescriptorContext for this call. </param>
        /// <param name="cultureInfo"> The CultureInfo which is respected when converting. </param>
        /// <param name="source"> The object to convert to a VirtualizationCacheLength. </param>
        public override object ConvertFrom(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object source)
        {
            if (source != null)
            {
                if (source is string)
                {
                    return (FromString((string)source, cultureInfo));
                }
                else
                {
                    //  conversion from numeric type
                    double value = Convert.ToDouble(source, cultureInfo);
                    return new VirtualizationCacheLength(value);
                }
            }
            throw GetConvertFromException(source);
 
        }
 
        /// <summary>
        /// ConvertTo - Attempt to convert a VirtualizationCacheLength to the given type
        /// </summary>
        /// <returns>
        /// The object which was constructoed.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// An ArgumentNullException is thrown if the example object is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// An ArgumentException is thrown if the object is not null and is not a VirtualizationCacheLength,
        /// or if the destinationType isn't one of the valid destination types.
        /// </exception>
        /// <param name="typeDescriptorContext"> The ITypeDescriptorContext for this call. </param>
        /// <param name="cultureInfo"> The CultureInfo which is respected when converting. </param>
        /// <param name="value"> The VirtualizationCacheLength to convert. </param>
        /// <param name="destinationType">The type to which to convert the VirtualizationCacheLength instance. </param>
        ///<SecurityNote>
        ///     Critical: calls InstanceDescriptor ctor which LinkDemands
        ///     PublicOK: can only make an InstanceDescriptor for VirtualizationCacheLength, not an arbitrary class
        ///</SecurityNote>
        [SecurityCritical]
        public override object ConvertTo(ITypeDescriptorContext typeDescriptorContext, CultureInfo cultureInfo, object value, Type destinationType)
        {
            if (destinationType == null)
            {
                throw new ArgumentNullException("destinationType");
            }
 
            if (value != null
                && value is VirtualizationCacheLength)
            {
                VirtualizationCacheLength gl = (VirtualizationCacheLength)value;
 
                if (destinationType == typeof(string))
                {
                    return (ToString(gl, cultureInfo));
                }
 
                if (destinationType == typeof(InstanceDescriptor))
                {
                    ConstructorInfo ci = typeof(VirtualizationCacheLength).GetConstructor(new Type[] { typeof(double), typeof(VirtualizationCacheLengthUnit) });
                    return (new InstanceDescriptor(ci, new object[] { gl.CacheBeforeViewport, gl.CacheAfterViewport }));
                }
            }
            throw GetConvertToException(value, destinationType);
        }
 
 
        #endregion Public Methods
 
        //-------------------------------------------------------------------
        //
        //  Internal Methods
        //
        //-------------------------------------------------------------------
 
        #region Internal Methods
 
        /// <summary>
        /// Creates a string from a VirtualizationCacheLength given the CultureInfo.
        /// </summary>
        /// <param name="cacheLength">VirtualizationCacheLength.</param>
        /// <param name="cultureInfo">Culture Info.</param>
        /// <returns>Newly created string instance.</returns>
        static internal string ToString(VirtualizationCacheLength cacheLength, CultureInfo cultureInfo)
        {
            char listSeparator = TokenizerHelper.GetNumericListSeparator(cultureInfo);
 
            // Initial capacity [64] is an estimate based on a sum of:
            // 24 = 2x double (twelve digits is generous for the range of values likely)
            //  2 = 2x separator characters
            //
            StringBuilder sb = new StringBuilder(26);
 
            sb.Append(cacheLength.CacheBeforeViewport.ToString(cultureInfo));
            sb.Append(listSeparator);
            sb.Append(cacheLength.CacheAfterViewport.ToString(cultureInfo));
            return sb.ToString();
        }
        /// <summary>
        /// Parses a VirtualizationCacheLength from a string given the CultureInfo.
        /// </summary>
        /// <param name="s">String to parse from.</param>
        /// <param name="cultureInfo">Culture Info.</param>
        /// <returns>Newly created VirtualizationCacheLength instance.</returns>
        static internal VirtualizationCacheLength FromString(string s, CultureInfo cultureInfo)
        {
            TokenizerHelper th = new TokenizerHelper(s, cultureInfo);
            double[] lengths = new double[2];
            int i = 0;
 
            // Peel off each double in the delimited list.
            while (th.NextToken())
            {
                if (i >= 2)
                {
                    i = 3;    // Set i to a bad value.
                    break;
                }
 
                lengths[i] = Double.Parse(th.GetCurrentToken(), cultureInfo);
                i++;
            }
 
            // We have a reasonable interpreation for one value (all four edges), two values (horizontal, vertical),
            // and four values (left, top, right, bottom).
            switch (i)
            {
                case 1:
                    return new VirtualizationCacheLength(lengths[0]);
 
                case 2:
                    // Should allowInfinity be false ??? (Rob)
                    return new VirtualizationCacheLength(lengths[0], lengths[1]);
            }
 
            throw new FormatException(SR.Get(SRID.InvalidStringVirtualizationCacheLength, s));
        }
 
    #endregion
 
    }
}