File: System\Drawing\ColorConverter.cs
Web Access
Project: src\src\libraries\System.ComponentModel.TypeConverter\src\System.ComponentModel.TypeConverter.csproj (System.ComponentModel.TypeConverter)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using System.Reflection;
 
namespace System.Drawing
{
    public class ColorConverter : TypeConverter
    {
        private static readonly Lazy<StandardValuesCollection> s_valuesLazy = new Lazy<StandardValuesCollection>(() =>
        {
            // We must take the value from each hashtable and combine them.
            var set = new HashSet<Color>(ColorTable.Colors.Values);
            return new StandardValuesCollection(set.OrderBy(c => c, new ColorComparer()).ToList());
        });
 
        public ColorConverter()
        {
        }
 
        public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
        {
            return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
        }
 
        public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType)
        {
            return destinationType == typeof(InstanceDescriptor) || base.CanConvertTo(context, destinationType);
        }
 
        public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
        {
            if (value is string strValue)
            {
                return ColorConverterCommon.ConvertFromString(strValue, culture ?? CultureInfo.CurrentCulture);
            }
 
            return base.ConvertFrom(context, culture, value);
        }
 
        public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
        {
            ArgumentNullException.ThrowIfNull(destinationType);
 
            if (value is Color c)
            {
                if (destinationType == typeof(string))
                {
                    if (c == Color.Empty)
                    {
                        return string.Empty;
                    }
 
                    // If this is a known color, then Color can provide its own name.
                    // Otherwise, we fabricate an ARGB value for it.
                    if (ColorTable.IsKnownNamedColor(c.Name))
                    {
                        return c.Name;
                    }
                    else if (c.IsNamedColor)
                    {
                        return "'" + c.Name + "'";
                    }
 
                    culture ??= CultureInfo.CurrentCulture;
 
                    string sep = culture.TextInfo.ListSeparator + " ";
                    TypeConverter intConverter = TypeDescriptor.GetConverterTrimUnsafe(typeof(int));
                    string?[] args;
                    int nArg = 0;
 
                    if (c.A < 255)
                    {
                        args = new string?[4];
                        args[nArg++] = intConverter.ConvertToString(context, culture, (object)c.A);
                    }
                    else
                    {
                        args = new string[3];
                    }
 
                    // Note: ConvertToString will raise exception if value cannot be converted.
                    args[nArg++] = intConverter.ConvertToString(context, culture, (object)c.R);
                    args[nArg++] = intConverter.ConvertToString(context, culture, (object)c.G);
                    args[nArg++] = intConverter.ConvertToString(context, culture, (object)c.B);
 
                    return string.Join(sep, args);
                }
                else if (destinationType == typeof(InstanceDescriptor))
                {
                    MemberInfo? member;
                    object[]? args = null;
 
                    if (c.IsEmpty)
                    {
                        member = typeof(Color).GetField("Empty");
                    }
                    else if (ColorTable.IsKnownNamedColor(c.Name))
                    {
                        member = typeof(Color).GetProperty(c.Name) ?? typeof(SystemColors).GetProperty(c.Name);
                    }
                    else if (c.A != 255)
                    {
                        member = typeof(Color).GetMethod("FromArgb", new Type[] { typeof(int), typeof(int), typeof(int), typeof(int) });
                        args = new object[] { c.A, c.R, c.G, c.B };
                    }
                    else if (c.IsNamedColor)
                    {
                        member = typeof(Color).GetMethod("FromName", new Type[] { typeof(string) });
                        args = new object[] { c.Name };
                    }
                    else
                    {
                        member = typeof(Color).GetMethod("FromArgb", new Type[] { typeof(int), typeof(int), typeof(int) });
                        args = new object[] { c.R, c.G, c.B };
                    }
 
                    Debug.Assert(member != null, "Could not convert color to member. Did someone change method name / signature and not update ColorConverter?");
                    if (member != null)
                    {
                        return new InstanceDescriptor(member, args);
                    }
                    else
                    {
                        return null;
                    }
                }
            }
 
            return base.ConvertTo(context, culture, value, destinationType);
        }
 
        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context)
        {
            return s_valuesLazy.Value;
        }
 
        public override bool GetStandardValuesSupported(ITypeDescriptorContext? context) => true;
 
        private sealed class ColorComparer : IComparer<Color>
        {
            public int Compare(Color left, Color right) => string.CompareOrdinal(left.Name, right.Name);
        }
    }
}