(X) Hide this
    • Login
    • Join
      • Say No Bots Generate New Image
        By clicking 'Register' you accept the terms of use .

Red-To-Green scale using an IValueConverter

(5 votes)
Marcel du Preez
>
Marcel du Preez
Joined Jun 09, 2010
Articles:   3
Comments:   0
More Articles
2 comments   /   posted on Jun 15, 2010
Categories:   Data Binding , General

This article is compatible with the latest version of Silverlight.


Introduction

Recently I have been working on a project, where a certain task's completion needs to be visually indicated in some graphic way. I settled on creating a style for the ProgressBar control, with a changing background color depending on the current value of the ProgressBar.

HSV (Hue-Saturation-Value)

From Wikipedia :

"HSL and HSV are the two most common cylindrical-coordinate representations of points in an RGB color model, which rearrange the geometry of RGB in an attempt to be more perceptually relevant than the cartesian representation."

HSV is a different way of representing a color (as opposed to RGB, where R indicates a value from 0 to 255 that "controls the amount of red", G for green and B for Blue). Have a look at the link above for an in-depth discussion.

I'll be using HSV to do my color change. By keeping the Saturation and Value values constant, and changing the Hue based on my progress, the color will change between Red, Orange, Yellow and finally Green.

IValueConverter

IValueConverter is an interface that can be implemented in WPF/Silverlight to provide a declarative way to convert properties from one datatype to another. I'll be using it to convert from my current progress (a int value between 0 and 100) and a Brush, which is what my ProgressBar expects as a background.

Create a class, and have it implement the IValueConverter interface, as below : 


public
class RedToGreenScaleConverter : IValueConverter
{
    #region IValueConverter Members  
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new SolidColorBrush(ColorFromHSV((double)value, 1, 1));
    }
  
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture    {
        return null;
    }
    #endregion
}

IValueConverter implements two methods : Convert, and ConvertBack. The titles should be self-explanatory. In ConvertBack, I return a null value (I don't want to convert a Brush to an int in my application). In Convert, I return a new SolidColorBrush, which I need to provide with one argument : a Color.

The Color is returned from a custom method call ColorFromHSV. It calculates the RGB values for specific H, S and V values (which are provided as arguments) :

private static Color ColorFromHSV(double hue, double saturation, double value)
{
            int hi = (int)(Math.Floor(hue / 60)) % 6;
            double f = hue / 60 - Math.Floor(hue / 60);  
            value = value * 255;
            int v = (int)(value);
            int p = (int)(value * (1 - saturation));
            int q = (int)(value * (1 - f * saturation));
            int t = (int)(value * (1 - (1 - f) * saturation));
  
            if (hi == 0)
                return Color.FromArgb(255, (byte)v, (byte)t, (byte)p);
            else if (hi == 1)
                return Color.FromArgb(255, (byte)q, (byte)v, (byte)p);
            else if (hi == 2)
                return Color.FromArgb(255, (byte)p, (byte)v, (byte)t);
            else if (hi == 3)
                return Color.FromArgb(255, (byte)p, (byte)q, (byte)v);
            else if (hi == 4)
                return Color.FromArgb(255, (byte)t, (byte)p, (byte)v);
            else
                return Color.FromArgb(255, (byte)v, (byte)p, (byte)q);
}

This code was adapted from here.

ProgressBar Style

To implement this in a ProgressBar, I needed to create a new style. Using Expression Blend, add a ProgressBar to your control/window/page, right-click on it in the Objects and Timeline window, select Edit Templates and Edit a Copy... :

This will generate a Style for a ProgressBar in the location you specify, based on the current style. Because I had no style specified, the default style is returned.

The style consists of a lot of XAML... but the part I'm interested in is called "Indicator", a rectangle. This rectangle contracts/expands depending on the Value property of the ProgressBar. I'll be changing it's Fill property, but first, a namespace declaration :

xmlns:converters="clr-namespace:ConverterDemo"

and a reference to my converter in the Resources section

<Window.Resources>
        <converters:RedToGreenScaleConverter x:Key="redGreenScale" />
</Window.Resources>

and finally, changing the Fill property : 

<Rectangle x:Name="Indicator" Fill="{TemplateBinding Value, Converter={StaticResource redGreenScale}}"/>

[Update] : Thanks to Waqas for pointing out that the previous code snippet only works in WPF. For it to work in Silverlight, you need to use a RelativeSource Binding, as follows :

 <Rectangle x:Name="Indicator" 
            Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, 
                  Path=Value, 
                  Converter={StaticResource redGreenScale}}" 

[Another update] : You can also use the Progressbar’s Foreground property with the RelativeSource Binding… eliminating the need for the template :

 <ProgressBar Foreground="{Binding RelativeSource={RelativeSource Self}, 
              Path=Value, 
              Converter={StaticResource redGreenScale}}"

This piece of code says that the Fill property should be set to the value of the ProgressBar's Value property (via TemplateBinding, check Bea Stollnitz's blog for a simple explanation), converted by using the RedToGreenScaleConverter. So, everytime the ProgressBar's value changes, that value will be converted to a Color by the converter.

Result

This is what the ProgressBar looks like at the indicated values :

Ciao!
Marcel du Preez
marcel@inivit.com


Subscribe

Comments

  • -_-

    RE: Red-To-Green scale using an IValueConverter


    posted by Waqas on Jul 22, 2010 09:15
    <Rectangle x:Name="Indicator" Fill="{TemplateBinding Value, Converter={StaticResource redGreenScale}}"/>

    The above xaml code doesn't work in silverlight just replace with the following

    <Rectangle x:Name="ProgressBarIndicator" Fill="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Converter={StaticResource progressconverter}}" HorizontalAlignment="Left" Margin="{TemplateBinding BorderThickness}" RadiusY="1.5" RadiusX="1.5" StrokeThickness="0.5"/>
  • -_-

    RE: Red-To-Green scale using an IValueConverter


    posted by Marcel on Sep 07, 2010 13:34

    Hi Waqas...

    Thanks! I've updated the article to include your fix. Also note another method, not requiring a template.

    Marcel

Add Comment

Login to comment:
  *      *