Make your WPF buttons color hot-track! - Rudi Grobler
Wednesday, October 14, 2009 9:16 AM rudi

Make your WPF buttons color hot-track!

One of the cool new features of the Windows 7 taskbar is that all running applications gives you this nice feedback that its running using the color hot-track “feature”

“Color hot-track is a small touch that typifies the new taskbar’s personality. When a person moves her mouse over a running program on the taskbar, she will be pleasantly surprised to find that a light source tracks her mouse and the color of the light is actually based on the icon itself. We calculate the most dominant RGB of the icon and dynamically paint the button with this color. Color hot-track provides a delight factor, it offers feedback that a program is running and it showcases a program’s icon. We’ve always believed that programs light up the Windows platform and now, we’re returning the favor.”

Engineering Windows 7 - The Windows 7 Taskbar

A while back I read a article from Grant Hinkson called “McGuffin”-Enabling Image Converter!

“This converter is bound to an Image’s Source property and then returns an “averaged” Color”

I “borrowed” his idea and created my own value converter that takes a icon (BitmapFrame), calculates the average color and the create a linear gradient brush using this color!

public class IconToAvgColorBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        {
            return new SolidColorBrush(Colors.Transparent);
        }

        MemoryStream stream = new MemoryStream();
        if (value is BitmapFrame)
        {
            BitmapFrame frame = (BitmapFrame)value;
            System.Windows.Media.Imaging.BmpBitmapEncoder e = new BmpBitmapEncoder();
            e.Frames.Add(frame);
            e.Save(stream);
        }

        try
        {
            Bitmap bitmap = new Bitmap(stream);

            int tr = 0;
            int tg = 0;
            int tb = 0;

            for (int x = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    System.Drawing.Color pixel = bitmap.GetPixel(x, y);
                    tr += pixel.R;
                    tg += pixel.G;
                    tb += pixel.B;
                }
            }

            byte r = (byte)Math.Floor((double)(tr / (bitmap.Height * bitmap.Width)));
            byte g = (byte)Math.Floor((double)(tg / (bitmap.Height * bitmap.Width)));
            byte b = (byte)Math.Floor((double)(tb / (bitmap.Height * bitmap.Width)));

            LinearGradientBrush brush = new LinearGradientBrush();
            brush.EndPoint = new System.Windows.Point(0.5, 1.0);
            brush.StartPoint = new System.Windows.Point(0.5, 0.0);
            brush.GradientStops.Add(new GradientStop(System.Windows.Media.Color.FromArgb(0xFF, r, g, b), 0.00));
            brush.GradientStops.Add(new GradientStop(System.Windows.Media.Color.FromArgb(0x00, r, g, b), 1.00));
            return brush;
        }
        catch (Exception)
        {
            return new SolidColorBrush(Colors.Transparent);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}

[DISCLAIMER] This code still needs some error checking…

The next part could be re-factored into a control but I just wanted to show the basics! I create a style that changes the background color from transparent to the average color using triggers!

<local:IconToAvgColorBrushConverter x:Key="iconToAvgColorBrushConverter"/>

<Style x:Key="ColorHotTrackButton" TargetType="{x:Type Button}" BasedOn="{x:Null}">
    <!-- Removed for brevity -->
</Style>

And to use it is very simple!

<Button Margin="2.5,0,2.5,0" Style="{DynamicResource ColorHotTrackButton}" Background={Binding Path=Source, Converter={StaticResource iconToAvgColorBrushConverter}, ElementName=explorerIcon, Mode=Default}">
    <Image Source="Assets/IE.ico" Width="32" Height="32" Margin="12.5,0,12.5,0" x:Name="ieIcon" />        
</Button>

Here is the end result…

Source

Related Posts – Anatomy of the Windows 7 taskbar series

Filed under: , , , , ,

Comments

# Make your WPF buttons color hot-track! - Rudi Grobler

Wednesday, October 14, 2009 9:22 AM by DotNetShoutout

Thank you for submitting this cool story - Trackback from DotNetShoutout

# Make your WPF buttons color hot-track

Wednesday, October 14, 2009 9:22 AM by DotNetKicks.com

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# re: Make your WPF buttons color hot-track!

Wednesday, October 14, 2009 10:49 AM by Ismail Lunat

Nice ... Thanks

# Dew Drop &#8211; October 14, 2009 | Alvin Ashcraft&#039;s Morning Dew

Wednesday, October 14, 2009 3:19 PM by Dew Drop – October 14, 2009 | Alvin Ashcraft's Morning Dew

Pingback from  Dew Drop &#8211; October 14, 2009 | Alvin Ashcraft&#039;s Morning Dew

# re: Make your WPF buttons color hot-track!

Friday, October 16, 2009 5:00 AM by Raul Mainardi Neto

Amazing code Rudi, as usual actually, but what bugs me is that on your BindingExpression you bind to the FrameworkElement by name (by using ElementName), which is usually something that I try to avoid, but since the Binding class is dead clever we can use the following to avoid the explicit element name to the binding:

Background="{Binding Path=Content.Source, Converter={StaticResource iconToAvgColorBrushConverter}, RelativeSource={RelativeSource Self}, Mode=Default}"

of course this only works if you ensure that your first level FrameworkElement nested in the  button logical tree has a Source property, but for sure looks pretty cool.

Cheers mate

All best

Raul

# re: Make your WPF buttons color hot-track!

Friday, October 16, 2009 7:09 AM by rudi

Tnx for the comment Raul! Your idea seems solid and I agree that the only problem is that you now have to somehow ensure that its a icon! There is 2 other ways to solve this problem: The prevered way imo is to refactor it out into a seperate control! Or you can use your method but make the value converter more "clever"... ie. if its a button and the content is a framework element, convert it to a bitmap first!!! This will give you the same feature (the color hot-track) even if the content is some crazy vector art! I just wanted to keep the article as simple as possible! Another interesting thing to play with is do the actual mouse tracking and change the linear gradient brush center? just a thought...

Tnx again for the kind comments...

Rudi

# re: Make your WPF buttons color hot-track!

Friday, October 16, 2009 5:57 PM by Raul Mainardi Neto

Rudi, Tnx for the quick reply Rudi, I have written some aditional content for your code and would like to have your permission to post it. Would you mind?

All best

# Windows Presentation Foundation | Jamming Online

Saturday, October 17, 2009 2:03 PM by Windows Presentation Foundation | Jamming Online

Pingback from  Windows Presentation Foundation | Jamming Online

# re: Make your WPF buttons color hot-track!

Wednesday, October 21, 2009 7:43 AM by rudi

Raul,

No problem...