在C#中将字符串转换为颜色

72
我遇到了一个问题,如何将输入的字符串“RED”转换为C#中实际的颜色类型Color.Red?有没有更好的方法?
我可以考虑使用switch语句和每个颜色类型的case语句,但我认为这不够聪明。
10个回答

112
 Color red = Color.FromName("Red");   

根据MSDN上的内容,无法确定是否对大小写敏感,因此很可能是对大小写敏感的。(更新:显然不是。)

据我所知,ColorTranslator.FromHtml 也是区分大小写的。

如果 Color.FromName 找不到匹配项,则返回 new Color(0,0,0);

如果 ColorTranslator.FromHtml 找不到匹配项,则会抛出异常。

更新:

由于你正在使用Microsoft.Xna.Framework.Graphics.Color,情况有些棘手:

using XColor = Microsoft.Xna.Framework.Graphics.Color;
using CColor = System.Drawing.Color;

 CColor clrColor = CColor.FromName("Red"); 
 XColor xColor = new XColor(clrColor.R, clrColor.G, clrColor.B, clrColor.A);

嘿,詹姆斯,感谢你的评论。由于我正在XNA GameStudio中开发这个程序,在输入了你的代码后,程序报错: 错误1:'Microsoft.Xna.Framework.Graphics.Color'不包含名称为'FromName'的定义,也没有接受类型为'Microsoft.Xna.Framework.Graphics.Color'的第一个参数的扩展方法'FromName'(是否缺少使用指令或程序集引用?)C:\ Users \ Guoguo \ Desktop \ MapWorld2 \ MapWorld \ GameObject.cs 194 27 MapWorld你知道这个错误是什么吗?谢谢。 - Kevin
3
谢谢肯定未找到匹配项时不同行为的提及。 - Davy8
Microsoft.Xna.Framework 不是正确的命名空间。请使用 System.Drawing。 - StingyJack
3
@StingyJack:你不能要求楼主改变他感兴趣的类型!不过,如果一开始就被告知他感兴趣的类型会更好... - Jon Skeet
编辑假设System.Drawing.Color中的颜色集与XNA Color类型中的颜色集相同。这可能是真的,也可能不是...并且可能很重要(OP可能对System.Drawing中的颜色范围感到满意)。 - Jon Skeet
显示剩余2条评论

22
System.Drawing.Color myColor = System.Drawing.ColorTranslator.FromHtml("Red");

(如果您想接受HTML样式的十六进制颜色,请使用我的方法。)


15

如果一开始您能提出对哪种Color类型感兴趣就好了……

一个简单的方法是通过反射构建一个字典:

public static class Colors
{
    private static readonly Dictionary<string, Color> dictionary =
        typeof(Color).GetProperties(BindingFlags.Public | 
                                    BindingFlags.Static)
                     .Where(prop => prop.PropertyType == typeof(Color))
                     .ToDictionary(prop => prop.Name,
                                   prop => (Color) prop.GetValue(null, null)));

    public static Color FromName(string name)
    {
        // Adjust behaviour for lookup failure etc
        return dictionary[name];
    }
}

首次查找会比较慢(因为它需要使用反射来查找所有属性),但之后应该非常快。

如果你希望不区分大小写,可以在ToDictionary调用中传递类似StringComparer.OrdinalIgnoreCase的额外参数。如果需要,可以轻松添加TryParse等方法。

当然,如果你只需要在一个地方使用,就不必费心创建单独的类等等 :)


看起来这是回答这个问题的最佳方法:https://dev59.com/yE_Ta4cB1Zd3GeqPBYAj - Bennor McCarthy

12

这取决于你正在寻找什么,如果你需要System.Windows.Media.Color(比如在WPF中),那么非常容易:

System.Windows.Media.Color color = (Color)System.Windows.Media.ColorConverter.ConvertFromString("Red");//or hexadecimal color, e.g. #131A84

8

由于OP在评论中提到他正在使用Microsoft.Xna.Framework.Graphics.Color而不是System.Drawing.Color,因此您可以首先创建一个System.Drawing.Color,然后将其转换为Microsoft.Xna.Framework.Graphics.Color

public static Color FromName(string colorName)
{
    System.Drawing.Color systemColor = System.Drawing.Color.FromName(colorName);   
    return new Color(systemColor.R, systemColor.G, systemColor.B, systemColor.A); //Here Color is Microsoft.Xna.Framework.Graphics.Color
}

第二行应该是: Color xnaColor = new Color(systemColor.R, systemColor.G, systemColor.B, systemColor.A);但我相信这是实现Robert所要求的最简单的方法。 - Romias
...还需要添加一个正确的return语句 :) - Peter Lillevold

5

我发现通过xml字符串传输颜色的方法如下:

Color x = Color.Red; // for example
String s = x.ToArgb().ToString()
... to/from xml ...
Int32 argb = Convert.ToInt32(s);
Color red = Color.FromArgb(argb);

3
这个方案很适合我的需求。希望有人能够用得上它...
    public static Color FromName(String name)
    {
        var color_props= typeof(Colors).GetProperties();
        foreach (var c in color_props)
            if (name.Equals(c.Name, StringComparison.OrdinalIgnoreCase))
                return (Color)c.GetValue(new Color(), null);
        return Colors.Transparent;
    }

2
最简单的方法:
string input = null;
Color color = Color.White;

TextBoxText_Changed(object sender, EventsArgs e)
{
   input = TextBox.Text;
}

Button_Click(object sender, EventsArgs e)
{
   color = Color.FromName(input)
}

1
以下代码可以根据名称十六进制已知名称生成颜色。
Color beige = StringToColor("Beige");
Color purple = StringToColor("#800080");
Color window = StringToColor("Window");

public static Color StringToColor(string colorStr)
{
    TypeConverter cc = TypeDescriptor.GetConverter(typeof(Color));
    var result = (Color)cc.ConvertFromString(colorStr);
    return result;
}

这段代码摘自Jo Albahari的《C# in a Nutshell》。

当我尝试这样做时,我得到了“System.NotSupportedException: 'TypeConverter无法从System.String进行转换。'” - GuidoG

-2

我以前用过类似的东西:

        public static T CreateFromString<T>(string stringToCreateFrom) {

        T output = Activator.CreateInstance<T>();

        if (!output.GetType().IsEnum)
            throw new IllegalTypeException();

        try {
            output = (T) Enum.Parse(typeof (T), stringToCreateFrom, true);
        }
        catch (Exception ex) {
            string error = "Cannot parse '" + stringToCreateFrom + "' to enum '" + typeof (T).FullName + "'";
            _logger.Error(error, ex);
            throw new IllegalArgumentException(error, ex);
        }

        return output;
    }

@Jon 我把 ConsoleColor 搞混了。不过,相同的逻辑仍然适用... 对吧?他可以对属性名称进行不区分大小写的比较并返回结果,而不是使用 Enum.Parse()(显然要删除 IsEnum 检查)。 - Skyler
我认为每次通过反射查找属性都会相对痛苦。在我看来,最好是像我的答案一样建立一个字典。 - Jon Skeet
@Jon 是的,我刷新后看到了。 - Skyler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接