Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

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

5.00/5 (2 votes)
20 Mar 2011CPOL 23.1K  
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)