Using all of the WPF Colors in Silverlight

August 10, 2009 06:28

In my recent TagCloud control series, I listed out a number of enhancements I wanted to implement. One of those enhancements was the ability to specify the tag item font color (as well as the mouseover/hover color as each tag is a hyperlink) as an initial parameter. When you consider deploying the control to more than one web site, the need for such customizations should be clear.

Ideally, the colors could be specified either by WPF color name or by hex representation (see 'TagColor' and 'TagHoverColor' in the following code snippet):

   1: InitParams = string.Format (
   2:     "ControlId=silverlightTagCloud,ControlHostId=silverlightControlHost,
   3:     TagThreshold=2,FontFamily=Arial,TagColor=#5C80B1,TagHoverColor=DodgerBlue,MinimumFontSize=12");
None of this presents any real challenge until you realize that the Silverlight Colors class does not support the same, full range of color names as WPF. From the MSDN page, the Silverlight Colors class supports only:

image

That's a far cry from the range supported by the WPF Colors class.

In a Silverlight code-behind you can see this limited range as:

image

Since I want users of the TagCloud control to be able to specify, by name, the full range of WPF colors, I knew I had some researching to do.

I started by asking a question on stackoverflow.com. That led me here and, ultimately, to work done by shacktoms on the Silverlight Forum. A big thanks goes to shacktoms as I was able to take his code, add a few tweaks of my own, and get up and running in no time.

Ultimately, we wind up with the new ColorName class, which uses the hex representation of each WPF color, exposing each as a static member (full list omitted for brevity):

   1: public static readonly ColorName AliceBlue = 0xFFF0F8FF;
   2: public static readonly ColorName AntiqueWhite = 0xFFFAEBD7;
   3: public static readonly ColorName Aqua = 0xFF00FFFF;
   4: public static readonly ColorName Aquamarine = 0xFF7FFFD4;
   5: public static readonly ColorName Azure = 0xFFF0FFFF;
   6: public static readonly ColorName Beige = 0xFFF5F5DC;
   7: public static readonly ColorName Bisque = 0xFFFFE4C4;
   8: public static readonly ColorName Black = 0xFF000000;
   9: public static readonly ColorName BlanchedAlmond = 0xFFFFEBCD;
  10: public static readonly ColorName Blue = 0xFF0000FF;
  11: public static readonly ColorName BlueViolet = 0xFF8A2BE2;
  12: public static readonly ColorName Brown = 0xFFA52A2A;
  13: public static readonly ColorName BurlyWood = 0xFFDEB887;
  14: public static readonly ColorName CadetBlue = 0xFF5F9EA0;
  15: public static readonly ColorName Chartreuse = 0xFF7FFF00;
  16: public static readonly ColorName Chocolate = 0xFFD2691E;
  17: public static readonly ColorName Coral = 0xFFFF7F50;
  18: public static readonly ColorName CornflowerBlue = 0xFF6495ED;

So, what happens is the color is specified as an initial parameter into the Silverlight control (see first code snippet above) either by name or by hex representation. The control then translates this textual format into its corresponding RGB parts and assigns that value to the brush used for, for example, tag font color.

In the control, we'll have two brushes (this is a bit of a sneak preview into the next version of the TagCloud):

   1: public SolidColorBrush TagBrush { get; private set; }
   2: public SolidColorBrush TagColorHoverBrush { get; private set; }

In the TagCloud control's Page constructor, we'll look for the initial parameters 'TagColor' and 'TagHoverColor':

   1: if (!string.IsNullOrEmpty (tagColor))
   2: {
   3:     try
   4:     {
   5:         var colorName = new ColorName (tagColor);
   6:         TagBrush = new SolidColorBrush (colorName);
   7:     }
   8:     catch (Exception)
   9:     {
  10:         TagBrush = _defaultTagItemBrush;
  11:     }
  12: }
  13: else
  14: {
  15:     TagBrush = _defaultTagItemBrush;
  16: }
  17:  
  18: if (!string.IsNullOrEmpty (tagHoverColor))
  19: {
  20:     try
  21:     {
  22:         var colorName = new ColorName (tagHoverColor);
  23:         TagColorHoverBrush = new SolidColorBrush (colorName);
  24:     }
  25:     catch (Exception)
  26:     {
  27:         TagColorHoverBrush = _defaultTagItemHoverBrush;
  28:     }
  29: }
  30: else
  31: {
  32:     TagColorHoverBrush = _defaultTagItemHoverBrush;
  33: }

The important stuff is on lines 5-6 and 22-23, where we create a new ColorName and then assign it to each of our brushes. Taking a look at the ColorName constructor:

   1: public ColorName (string color)
   2: {
   3:     if (string.IsNullOrEmpty (color)) throw new ArgumentOutOfRangeException ();
   4:  
   5:     if (color[0] == '#')    // see if first position is the hash character
   6:     {
   7:         _colorValue = GetColorFromHexString (color);
   8:     }
   9:     else
  10:     {
  11:         var fieldInfo = GetType ().GetField (color);
  12:         _colorValue = (ColorName) fieldInfo.GetValue (this);    
  13:     }
  14: }

If the color is in hex format we use the GetColorFromHexString method. If not, we use a bit of reflection to match the specified color name with its static member variable equivalent. Ultimately, we end up with a numeric representation of the color that we can then pass into SolidColorBrush to create our color brush.

Here's GetColorFromHexString for reference:

   1: private static uint GetColorFromHexString (string hexFormattedColor)
   2: {
   3:     if (hexFormattedColor[0] != '#') throw new ArgumentOutOfRangeException (hexFormattedColor, "The color value is not in the expected hex format.");
   4:  
   5:     var hexColor = hexFormattedColor.Substring (1);    // take out the leading '#'
   6:  
   7:     switch (hexColor.Length)
   8:     {
   9:         case 6:
  10:  
  11:             // convert, add default alpha value
  12:             return (UInt32.Parse ("FF" + hexColor, System.Globalization.NumberStyles.HexNumber));
  13:  
  14:         case 8:
  15:  
  16:             return (UInt32.Parse (hexColor, System.Globalization.NumberStyles.HexNumber));
  17:  
  18:         default:
  19:  
  20:             throw new ArgumentOutOfRangeException (hexColor, "The color value is not in the expected hex format.");
  21:     }
  22: }

Conclusion

Accessing the full range of WPF colors through Silverlight was important functionality I wanted in my TagCloud control. But the ColorName class can be used anywhere in Silverlight. Feel free to download and use as you see fit.

Download: ColorName.cs.zip 

References

Colors in Silverlight: I need a bigger box of crayons!

WPF Colors

Silverlight colors


Comments

All comments are moderated and require approval before display. Thanks for your understanding.

Add comment


 


[b][/b] - [i][/i] - [u][/u] - [q][/q]



Preview