Get RGB Values from WPF Color

Recently, I have been setting up a lot of WPF styles for an application I am working on. During this project, I needed to set a lot of colors. Instead of hard-coding colors, I use resources. For example, I am using the <DropShadowEffect> on many of my controls. This <DropShadowEffect> element has a “Color” attribute that you can set as shown in the code below:

<Border.Effect>
  <DropShadowEffect
       BlurRadius="10"
       Color="Gray" />
</Border.Effect>

Instead of hard-coding the color “Gray”, I would like to use a resource. I can’t just create a string resource and put that into the Color attribute. You must use a <Color> resource. Thus, I need to create a Color resource that looks like the following:

<Color x:Key="pdsaDropShadowEffectColor"
       R="128"
       B="128"
       G="128" />

Well, I don’t know about you, but I do not remember all of the (R)ed, (G)reen, and (B)lue color numbers off the top of my head. Thus, I needed a little utility that would help me get these numbers for the color I was looking for. In Figure 1 you can see a utility I wrote to help me do this.
 
Color to RGB

Figure 1: Utility to display all the WPF colors and retrieve the RGB values

Loading a List Box with WPF Colors

The first thing this utility needs to do is to load all the WPF colors into a list box. You can get the complete list of Colors using an ObjectDataProvider object, however setting up the ObjectDataProvider can be a little tricky. One thing that helps me immensely – and I hope will work for you -- is to write a little code that will return a collection of items. Once I have that, I usually find it is very easy to convert that code to use an ObjectDataProvider.

To retrieve the WPF Colors is also a little tricky, as the Colors class contains individual static/Shared properties, one property to represent each color. So you need to use reflection to get the collection of properties. Each property of the Colors class is a Color object. So once you have each Color object, you then need all of its properties so you can retrieve the  Name property. Once you have the Name property you can bind that property to the list box shown in Figure 1. Below is some sample code you might write to retrieve and print out each individual color name from the Colors class. NOTE: This code is not used in this project, it is just here as an example of how to use reflection to get the list of properties of a Color object.

C#
using System.Reflection;
using System.Diagnostics;

private void GetColorEnumsAsString()
{
  PropertyInfo[] clrs = Type.GetType(
    "System.Windows.Media.Colors, PresentationCore,
       Version=3.0.0.0, Culture=neutral,
       PublicKeyToken=31bf3856ad364e35").GetProperties();

  foreach (PropertyInfo item in clrs)
  {
    Debug.WriteLine(item.Name);
  }
}

Visual Basic

Imports System.Reflection
Imports System.Diagnostics

Private Sub GetColorEnumsAsString()
  Dim clrs As PropertyInfo() = Type.GetType( _
    "System.Windows.Media.Colors, PresentationCore,
     Version=3.0.0.0, Culture=neutral,
     PublicKeyToken=31bf3856ad364e35").GetProperties()

  For Each item As PropertyInfo In clrs
    Debug.WriteLine(item.Name)
  Next
End Sub

In the above code, you first use the  GetType method of the Type class. You pass to this method the fully qualified class name including the namespace and the assembly information. For any class that is not in the System assembly, you need to use the full assembly qualification. Once you retrieve the Type, you call the GetProperites method on type to get a collection of PropertyInfo objects. It is in the PropertyInfo object that you can get the Name property. Since the name of the property is the name of the color, you bind the Name property to the list box.

Using the ObjectDataProvider

From the above code you can then figure out how to lay out your ObjectDataProvider, or in this case, two ObjectDataProvider objects. As you can see in the above code, you need to perform two operations to get the final collection. First, you call the GetType method, then you call GetProperties method. This means you need to use two ObjectDataProviders. The first ObjectDataProvider you create looks like the following:

<ObjectDataProvider MethodName="GetType"
                    ObjectType="{x:Type sys:Type}"
                    x:Key="odpColors">
  <ObjectDataProvider.MethodParameters>
    <sys:String>
         System.Windows.Media.Colors, PresentationCore,
         Version=3.0.0.0, Culture=neutral,
         PublicKeyToken=31bf3856ad364e35
    </sys:String>
  </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

In the above ObjectDataProvider you are creating an instance of the Type object located in the “sys” namespace. You need to add the “sys” namespace to your Window object. You do this by adding the following XAML within your Window declaration:

<Window x:Class="PDSAConvertColorToRGB.winMain"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  ...
The ObjectDataProvider has the ability to pass a parameter to the object you instantiate through the <ObjectDataProvider.MethodParameters>. The parameter in the MethodParameters is the exact string used in the code shown earlier. The next ObjectDataProvider uses the first ObjectDataProvider as its source of data and then calls the GetProperties method on this souce.
<ObjectDataProvider ObjectInstance="{StaticResource odpColors}"
                    MethodName="GetProperties"
                    x:Key="odpColorNames">
</ObjectDataProvider>

For this second ObjectDataProvider the data is the instance of the data of the first ObjectDataProvider. You call the GetProperties method on the data type in the first ObjectDataProvider to give you Color object collection to which you can bind to the ListBox control on the Window.

Defining the ListBox

Once you have the collection of Color objects you now bind them to the list box control. For this list box, you want to not only have the name of the color displayed, but also a display of the actual color. To accomplish this you use a DataTemplate and layout the display of each list item. Each list item will use a label for the name of the color, and will set the Fill attribute of a Rectangle control to display the actual color. A thin black border will be used around the Rectangle control to clearly define the color swatch.

<ListBox Name="lstColors"
         Height="200"
         TextSearch.TextPath="Name"
         IsTextSearchEnabled="True"
         ItemsSource="{Binding
               Source={StaticResource odpColorNames}}"
         SelectedValuePath="Name">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <Label Width="140"
               Margin="4"
               Content="{Binding Path=Name}" />
        <Border BorderBrush="Black"
                BorderThickness="1"
                Margin="4">
          <Rectangle Width="140"
                     Fill="{Binding Path=Name}" />
        </Border>
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>

The final piece of the list box control is the setting of the SelectedValuePath. Setting this value to Name will allow you to retrieve the name of the Color object and use that object to extract the Red, Green and Blue color values.

Getting the Color Object

After you select a specific color from the list box, you click on the Get Color button on the window. This button will fire its Click event procedure shown in the code below.

C#
private void btnGetColor_Click(object sender, RoutedEventArgs e)
{
  Color clr = new Color();

  clr = (Color)ColorConverter.ConvertFromString(
    lstColors.SelectedValue.ToString());

  lblRed.Content = clr.R.ToString();
  lblGreen.Content = clr.G.ToString();
  lblBlue.Content = clr.B.ToString();
}

Visual Basic
Private Sub btnGetColor_Click(ByVal sender As System.Object, _
 ByVal e As System.Windows.RoutedEventArgs)
  Dim clr As New Color()

  clr = DirectCast(ColorConverter.ConvertFromString( _
                   lstColors.SelectedValue.ToString()), Color)

  lblRed.Content = clr.R.ToString()
  lblGreen.Content = clr.G.ToString()
  lblBlue.Content = clr.B.ToString()
End Sub

You first retrieve the name of the color from the SelectedValue property of the list box. Then you use the ColorConverter class to convert the name of the color to an actual Color object. Once you have the Color object, you can now extract the R, G and B properties of the color and display those values in each of the appropriate labels.

Summary

With just a tiny little bit of code you are able to extract the R, G and B properties from a Color object. These values can then be used to create <Color> resources in WPF or Silverlight. This handy utility is also a good tutorial on data binding and how to work with reflection. I hope this sample helped you.

NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF: Color To RGB" from the drop-down.

Good Luck With Your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".

No Comments