Custom Markup Extensions in WPF
Thursday, September 25, 2008, 01:45 PM
Posted by Ruben Steins
A nice post by raasiel on dZone about writing a simple
Custom MarkupExtension.
He creates a MarkupExtension you can use to automatically create a lighter and darker shade of a color for MouseOver effects. Interesting, although he doesn't post the code to actually create a darker or lighter color.
After reading
A good introduction to the different color models that exist, I decided that
the easiest a way to achieve the lighter and darker colors would be to use the HSL colormodel and adjust the lightness. The selected color would have a L of 50%, the darker would have a bit less, the lighter a bit more.
Now, since WPF uses RGB by default, we have to do some conversion.
These code samples give a conversion algorithm, , and converting them to C# isn't really hard:
ColorHSL RGBtoHSL(Color colorRGB)
{
ColorHSL hsl = new ColorHSL();
float r, g, b, h, s, l; //this function works with floats between 0 and 1
r = colorRGB.R / 256.0f;
g = colorRGB.G / 256.0f;
b = colorRGB.B / 256.0f;
float maxColor = Math.Max(r, Math.Max(g, b));
float minColor = Math.Min(r, Math.Min(g, b));
//R == G == B, so it's a shade of gray
if ( r == g && r == b )
{
h = 0.0f; //it doesn't matter what value it has
s = 0.0f;
l = r; //doesn't matter if you pick r, g, or b
}
else
{
l = (minColor + maxColor) / 2;
if (l < 0.5) s = (maxColor - minColor) / (maxColor + minColor);
else s = (maxColor - minColor) / (2.0f - maxColor - minColor);
if(r == maxColor) h = (g - b) / (maxColor - minColor);
else if(g == maxColor) h = 2.0f + (b - r) / (maxColor - minColor);
else h = 4.0f + (r - g) / (maxColor - minColor);
h /= 6; //to bring it to a number between 0 and 1
if(h < 0) h ++;
}
hsl.H = (short)(h * 255);
hsl.L = (short)(l * 255);
hsl.S = (short)(s * 255);
return hsl;
}
So, if we have the color as HSL, we can simply change the lightness and get the light and dark variant:
ColorHSL lightColor = (short)(normalColor.H * 1.5);
ColorHSL darkColor = (short)(darkColor.H * 0.5);
After this we have to convert back to RGB (mind you, this code is needs some improvements):
Color HSLtoRGB(ColorHSL colorHSL)
{
double r, g, b, h, s, l; //this function works with floats between 0 and 1
double temp1, temp2, tempr, tempg, tempb;
h = colorHSL.H / 256.0;
s = colorHSL.S / 256.0;
l = colorHSL.L / 256.0;
//If saturation is 0, the color is a shade of gray
if (s == 0)
{
r = g = b = l;
}
else
{
//Set the temporary values
if (l < 0.5)
{
temp2 = l * (1 + s);
}
else
{
temp2 = (l + s) - (l * s);
}
temp1 = 2 * l - temp2;
tempr = h + 1.0 / 3.0;
if (tempr > 1)
{
tempr--;
}
tempg = h;
tempb = h - 1.0 / 3.0;
if (tempb < 0)
tempb++;
//Red
if (tempr < 1.0 / 6.0) r = temp1 + (temp2 - temp1) * 6.0 * tempr;
else if (tempr < 0.5) r = temp2;
else if (tempr < 2.0 / 3.0) r = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempr) * 6.0;
else r = temp1;
//Green
if (tempg < 1.0 / 6.0) g = temp1 + (temp2 - temp1) * 6.0 * tempg;
else if (tempg < 0.5) g = temp2;
else if (tempg < 2.0 / 3.0) g = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempg) * 6.0;
else g = temp1;
//Blue
if (tempb < 1.0 / 6.0) b = temp1 + (temp2 - temp1) * 6.0 * tempb;
else if (tempb < 0.5) b = temp2;
else if (tempb < 2.0 / 3.0) b = temp1 + (temp2 - temp1) * ((2.0 / 3.0) - tempb) * 6.0;
else b = temp1;
}
return Color.FromRgb(Convert.ToByte(r*255), Convert.ToByte(g*255), Convert.ToByte(b*255));
}
If you use this code to calculate the colors you get this:

With this code you can complete your custom Markup Extension.