WPF: ColorHelper - how to retrieve the name of a given color or to retrieve a color by its name

by Olaf Rabbachin 5. February 2010 19:47

Today I stumbled over a thread in the WPF forum in which the OP was looking for a way to retrieve the (known) name for a given color.
That is, given a color such as #FFB22222 (or ARGB :: 255, 178, 32, 32), to retrieve "Firebrick". What I thought was darn simple actually isn't, because System.Windows.Media.Colors is a class and thus exposes all (known) colors as properties (as opposed to System.Drawing.KnownColor which is an enum). So there really isn't any other way than to use reflection to obtain a list of all colors. Here's a little helper class that returns the name of a color passed to it:

Retrieving the name of a given Color object

/// <summary>
/// Returns the known name of the color passed (if found), or an empty string.
/// </summary>
/// <param name="clr">The color whose name is to be returned.</param>
/// <returns>
/// The name of the passed color resp. an empty string if 
/// no matching known color could be found.
/// </returns>
public static string GetKnownColorName(Color clr)
{
   Color clrKnownColor;

   //Use reflection to get all known colors
   Type ColorType = typeof(System.Windows.Media.Colors);
   PropertyInfo[] arrPiColors = ColorType.GetProperties(BindingFlags.Public | BindingFlags.Static);

   //Iterate over all known colors, convert each to a <Color> and then compare
   //that color to the passed color.
   foreach (PropertyInfo pi in arrPiColors)
   {
      clrKnownColor = (Color)pi.GetValue(null, null);
      if (clrKnownColor == clr) return pi.Name;
   }

   return string.Empty;
}

If you call the above method with i.e. ...

string strColorName = GetKnownColorName(Color.FromArgb(255, 178, 32, 32));
MessageBox.Show(strColorName == "" ? "(None found)" : strColorName);

... the MessageBox will show "Firebrick".

 

Update to the above (Feb 13 2010)

I just updated the code for the method above after it became obvious that the GetHashCode() method is not returning unique values. I did a bit of searching in order to find out more about that, but couldn't find anything; the docs are no help at all with this respect or even when it comes to the reason for the existance of this method in the first place.

Actually, I don't have the slightest idea as to how the hashes couldn't be unique - colors resp. their ARGB values are uniqe in itself after all. However, the hashes for Colors.White and Colors.Blue are equal. Now if that isn't plain stupid! Lesson learned: never assume anything ...

Thanks to Pedro for catching this (see the comments).

 

Retrieving a list with all known colors (names + Color objects)

If you actually need a list with all color values and their name-counterparts (might make sense if you need this frequently), here's another little helper-method that will return all known colors along with the name of each color:

/// <summary>
/// Returns a list containing all known colors, each as a KeyValuePair with the name
/// as the key and the Color as the value.
/// </summary>
public static List<KeyValuePair<string, Color>> GetKnownColors()
{
   List<KeyValuePair<string, Color>> lst = new List<KeyValuePair<string, Color>>();
   Type ColorType = typeof(System.Windows.Media.Colors);
   PropertyInfo[] arrPiColors = ColorType.GetProperties(BindingFlags.Public | BindingFlags.Static);

   foreach (PropertyInfo pi in arrPiColors)
      lst.Add(new KeyValuePair<string, Color>(pi.Name, (Color)pi.GetValue(null, null)));
   return lst;
}

You could use the above in various ways, here's just one sample:

Color clr = Color.FromArgb(255, 178, 32, 32);
List> lstKnownColors = GetKnownColors();
string strColorName = (
   from c in lstKnownColors
   where
      c.Value.A == clr.A &&
      c.Value.R == clr.R &&
      c.Value.G == clr.G &&
      c.Value.B == clr.B
   select c.Key
   ).FirstOrDefault();

 

Retrieving a color via its name

Last but not least, if you need to go the opposite way, how about another simple helper method:

 

/// <summary>
/// Returns the Color which is represented by the name passed.
/// </summary>
/// <param name="strColorName">The name of the Color to retrieve.</param>
/// <returns>Nullable color - either the found Color or null.</returns>
public static Color? GetColorByName(string strColorName)
{
   Color? clrResult = null;
   try
   {
      object value = ColorConverter.ConvertFromString(strColorName);
      if (null != value) clrResult = (Color)value; 
   }
   catch (Exception) { }

   return clrResult;
}

 

Update to the above (Feb 15 2010)

I've just updated the GetColorByName method after Richard pointed out that it was prone to fail if an invalid name or an empty string were passed (see the comments). I've only resolved for a general purpose handler rather than just to catch FormatExceptions.

 

Wrapping it all up

To simplify things, I dropped the above into a class that you can simply drop into your projects.
Download it here:

C# version: ColorHelpers.cs (3.43 kb)

VB version: ColorHelpers.vb (3.48 kb)

 

Happy coding!


Location: SinglePost

Tags: , , , , , ,

Utilities | WPF (.net)

Comments


Brazil Pedro 
February 12. 2010 19:47
Pedro
Hey Olaf, I'm testing it right now and seems like I found a problem.
Can you check if it's true or I am getting crazy?

I'm using your GetKnownColorName method and passing to it a Colors.White and it is returning "Blue".
Any Ideas why?


Brazil Pedro 
February 12. 2010 19:50
Pedro
Nevermind Olaf.
Changing the if condition to "if (clrKnownColor == clr)" works.
I'm sorry to bother you.


February 13. 2010 11:10
Olaf Rabbachin
Hi Pedro,

I'm using your GetKnownColorName method and passing to it a Colors.White and it is returning "Blue".
Any Ideas why?


good catch! When I wrote the method, I tested the GetHashCode() method with various colors and was convinced that it would return a unique value. I don't really understand what the hash could be used for; neither do I understand as to why it wouldn't be a unique value. Oh well, I changed the code that can be downloaded - thanks for pointing this out!


February 15. 2010 07:29
trackback
Windows Client Developer Roundup for 2/15/2010

This is Windows Client Developer roundup #11. The Windows Client Developer Roundup aggregates information


United Kingdom Richard 
February 15. 2010 20:54
Richard
ColorConverter.ConvertFromString will throw a FormatException if it can't parse the input as a valid colour. Also, it will return null if the input is null, which means your GetColorByName function will throw a NullReferenceException.

Try this instead:

public static Color? GetColorByName(string colorName)
{
    Color? result = null;
    if (!string.IsNullOrEmpty(colorName))
    {
        try
        {
            object value = ColorConverter.ConvertFromString(colorName);
            if (null != value) result = (Color)value;
        }
        catch (FormatException)
        {
        }
    }
    
    return result;
}


February 15. 2010 22:08
Olaf Rabbachin
Hi Richard,

thanks for pointing this out, you're right of course. Smile

Add comment


(Will show your Gravatar icon)

  Country flag

Click to change captcha   

biuquote
  • Comment
  • Preview
Loading



About

Hi and welcome to my blog!

I'm a developer from Germany, currently focusing on .Net and WPF.

More about me ...