[WPF] How to gray the icon of a MenuItem ?
Here is a question that a friend of mine asked me recently. Indeed, as a beginner with WPF, it thought that setting the property IsEnabled = false, on the MenuItem, will disable it. So, the following code:
<MenuItem Header="Edit">
<MenuItem x:Name="miPaste"
Header="Paste" IsEnabled="False" >
<MenuItem.Icon>
<Image Source="pack://application:,,,/Images/Paste.png"
/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
Does not deactivate the image, as you can see here:
To correct this, you have 2 choices:
- Use a second gray image which will be specified as the source for the control if this one is deactivated
- Use the class FormatConvertedBitmap to create a gray image
So I’ve created a little class, AutoGreyableImage, which allow you to have an image that will be turn in gray automatically when the control is desactivated.
Here is how you can use it:
<MenuItem Header="Edit">
<MenuItem x:Name="miPaste"
Header="Paste">
<MenuItem.Icon>
<local:AutoGreyableImage Source="pack://application:,,,/Images/Paste.png"
/>
</MenuItem.Icon>
</MenuItem>
</MenuItem>
And here is the implementation:
/// <summary>
/// Class used to have an image that is able to be gray when the control is not enabled.
/// Author: Thomas LEBRUN (http://blogs.developpeur.org/tom)
/// </summary>
public class AutoGreyableImage : Image
{
/// <summary>
/// Initializes a new instance of the <see cref="AutoGreyableImage"/> class.
/// </summary>
static AutoGreyableImage()
{
// Override the metadata of the IsEnabled property.
IsEnabledProperty.OverrideMetadata(typeof(AutoGreyableImage), new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnAutoGreyScaleImageIsEnabledPropertyChanged)));
}
/// <summary>
/// Called when [auto grey scale image is enabled property changed].
/// </summary>
/// <param name="source">The source.</param>
/// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
private static void OnAutoGreyScaleImageIsEnabledPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
{
var autoGreyScaleImg = source as AutoGreyableImage;
var isEnable = Convert.ToBoolean(args.NewValue);
if (autoGreyScaleImg != null)
{
if (!isEnable)
{
// Get the source bitmap
var bitmapImage = new BitmapImage(new Uri(autoGreyScaleImg.Source.ToString()));
// Convert it to Gray
autoGreyScaleImg.Source = new FormatConvertedBitmap(bitmapImage, PixelFormats.Gray32Float, null, 0);
// Create Opacity Mask for greyscale image as FormatConvertedBitmap does not keep transparency info
autoGreyScaleImg.OpacityMask = new ImageBrush(bitmapImage);
}
else
{
// Set the Source property to the original value.
autoGreyScaleImg.Source = ((FormatConvertedBitmap) autoGreyScaleImg.Source).Source;
// Reset the Opcity Mask
autoGreyScaleImg.OpacityMask = null;
}
}
}
}
Here is the result:
You can download the sources (and the demo) here: http://morpheus.developpez.com/wpf/DisableMenuItemIcon.zip/wpf/DisableMenuItemIcon.zip
Happy coding !