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:
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));
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.