Click here to Skip to main content
15,887,027 members
Articles / Desktop Programming / WPF
Tip/Trick

Image that is grayed when disabled, for use in buttons, etc.

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
20 Mar 2011CPOL 22.2K   4   6
AutoGrayImage: An image class that changes to grayscale when it becomes disabled.
Download GrayImage.zip - 61.83 KB

Introduction


A well known WPF misfeature is that images of disabled (toolbar or other) buttons, or menuitems, are not displayed in grayscale. There are three well known ways around:

  • Set the image's Opacity with a trigger.
  • Set the image's Effect.
  • Use a custom image class.

All three approaches have been used before. Here I give an implementation of the third way.

Using the code

<Button>
  <my:AutoGrayImage Source2="/GrayImage;component/Images/Tulips.png" />
</Button>  

In the XAML, just replace your Image with AutoGrayImage, and set Source2 instead of the Source property. Here is how the result looks:




The Code


You should also add the following class to your project:
C#
public class AutoGrayImage : Image
{
    public AutoGrayImage()
    {
        IsEnabledChanged += new
      DependencyPropertyChangedEventHandler(AutoGrayImage_IsEnabledChanged);
    }

    void AutoGrayImage_IsEnabledChanged(object sender,
                            DependencyPropertyChangedEventArgs e)
    {
        Source = IsEnabled?Source2:GrayedImage;
    }
    FormatConvertedBitmap GrayedImage = null;

    public static readonly DependencyProperty Source2Property =
                 DependencyProperty.Register("Source2", typeof(BitmapSource),
                        typeof(AutoGrayImage), new PropertyMetadata(null,
                        OnSource2Changed));
    /// <summary>
    /// Sets the image to be grayed, or not.
    /// </summary>
    public BitmapSource Source2
    {
        get { return (BitmapSource)GetValue(Source2Property); }
        set { SetValue(Source2Property, value); }
    }
    static void OnSource2Changed(DependencyObject sender,
                                  DependencyPropertyChangedEventArgs e)
    {
        AutoGrayImage s = sender as AutoGrayImage;
        if (s.Source2 == null)
        {
            s.GrayedImage = null;
        }
        else
        {
            s.GrayedImage = new FormatConvertedBitmap(s.Source2,
                                PixelFormats.Gray8, null, 0);
            s.OpacityMask = new ImageBrush(s.Source2);
        }
        s.AutoGrayImage_IsEnabledChanged(s, new
                             DependencyPropertyChangedEventArgs());
    }
}

I admit that introducing another Source property, i.e., Source2, is not entirely clean. However, it seemed to be the option with the best (cleanliness / lines of code written) ratio.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralThank you :D Pin
LevanenG27-Jan-12 3:26
LevanenG27-Jan-12 3:26 
QuestionCurious... Pin
Andrew Rissing20-Mar-11 16:41
Andrew Rissing20-Mar-11 16:41 
AnswerRe: Curious... Pin
Thomas Willwacher20-Mar-11 17:26
Thomas Willwacher20-Mar-11 17:26 
Performance is not so much an issue for me, ... the typical use-case is a 16x16 icon in a toolbar. I just wanted the standard behavior with minimum lines of code written.
(With my solution you need no additional code, not even set a trigger or style.)
Furthermore I wanted a clear licensing situation, so as to be able to include the code in other projects under CPOL.
Finally the pixelshader based effects require DirectX SDK to be installed to compile, or else you need to ship a separate dll.
Both options are o.k. when only the compiled application is distributed, but are a bit awkward, e.g., when publishing a control on CodeProject.

But I completely agree that for other users the Effect-option might be better. I didn't compare the various Grayscale effects out there, but if you can provide a link to a good one, I'd be happy to include it in the Tip.

P.S.: Initially I was also worried about shader effects not running on older hardware. But this is not an issue, as I read, except on some virtual machines.
GeneralRe: Curious... Pin
Andrew Rissing21-Mar-11 4:58
Andrew Rissing21-Mar-11 4:58 
GeneralNice Idea but... Pin
musters16-Mar-11 10:13
musters16-Mar-11 10:13 
GeneralRe: Nice Idea but... Pin
Thomas Willwacher16-Mar-11 11:04
Thomas Willwacher16-Mar-11 11:04 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.