5
votes

I'm populating a Ribbon (WPF) programmatically based on MS RibbonControlsLibrary (3.5.41019.1). All images (most noticeable large images) looks very bad and "pixly":

Screenshot from 2 Ribbon

  • The top screenshot is from the "pixly" Ribbon (Image scaling looking bad)
  • The bottom screenshot is taken from the same area in a window based on WinForms with the same source images (Image scaling looking good)
  • All images are saved in 32 bit PNG 48x48

I have tried to set the BitmapScalingMode to "HighQuality" without any effect, source code:

BitmapImage img = new BitmapImage();
try
{
    Uri uri = new Uri("pack://application:,,,/UIMainWindow;component/Resources/" + iPictureName);                
    img.BeginInit();
    img.SetValue(BitmapImage.CacheOptionProperty, BitmapCacheOption.OnLoad);
    RenderOptions.SetBitmapScalingMode(img, BitmapScalingMode.HighQuality);
    img.UriSource = uri;
    img.EndInit();
    img.Freeze();
}
catch (Exception ex)
{
    throw new Exception("Creation of image failed: " + ex.Message, ex);
}

Question Why is the scaling of the images looking bad? And how can I solve this?

4

4 Answers

1
votes

None of the other answers above worked for me so I started my own investigation. Resizing the images to 32x32 almost fixed the problem, but we have users with different DPI settings and the images wouldn't scale correctly on their machines. I should also note that I'm using the System.Windows.Controls.Ribbon assemly, which may behave a little differently than the RibbonControlsLibrary.

I found that the default ControlTemplate for the RibbonButton has specifically specified NearestNeighbor as the bitmap scaling option. The good news is that it's easy to override this control template by dropping a style into your Window's resources. The slightly bad news is that the control template is pretty verbose. I dumped the default ControlTemplate for the RibbonButton on my system to a file and just changed the bitmap scaling option.

First, you'll need this namespace declaration at the top of your file if you don't have it already:

xmlns:s="clr-namespace:System;assembly=mscorlib"

Then put this Style in your Window's resources in order to override the RibbonButton appearance:

<Style TargetType="RibbonButton">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="RibbonButton">
                <Border BorderThickness="{TemplateBinding Border.BorderThickness}" CornerRadius="{TemplateBinding RibbonControlService.CornerRadius}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" Name="OuterBorder" SnapsToDevicePixels="True">
                    <Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" CornerRadius="{TemplateBinding RibbonControlService.CornerRadius}" BorderBrush="#00FFFFFF" Name="InnerBorder">
                        <StackPanel Name="StackPanel">
                            <Image Source="{TemplateBinding RibbonControlService.LargeImageSource}" Name="PART_Image" Width="32" Height="32" Margin="{DynamicResource {ComponentResourceKey TypeInTargetAssembly=Ribbon, ResourceId=LargeImageMargin}}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" VerticalAlignment="Center" RenderOptions.BitmapScalingMode="HighQuality" />
                            <Grid Name="Grid" HorizontalAlignment="Center" VerticalAlignment="Center">
                                <RibbonTwoLineText TextAlignment="Center" LineHeight="13" LineStackingStrategy="BlockLineHeight" Text="{TemplateBinding RibbonControlService.Label}" Name="TwoLineText" Margin="1,1,1,0" HorizontalAlignment="Center" VerticalAlignment="Top" />
                            </Grid>
                        </StackPanel>
                    </Border>
                </Border>
                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding Path=ControlSizeDefinition.ImageSize, RelativeSource={RelativeSource Mode=Self}}" Value="Large">
                        <Setter Property="FrameworkElement.MinWidth">
                            <Setter.Value>
                                <s:Double>44</s:Double>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="FrameworkElement.Height">
                            <Setter.Value>
                                <s:Double>66</s:Double>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="FrameworkElement.MinHeight" TargetName="Grid">
                            <Setter.Value>
                                <s:Double>26</s:Double>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="RibbonTwoLineText.HasTwoLines" TargetName="TwoLineText">
                            <Setter.Value>
                                <s:Boolean>True</s:Boolean>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=ControlSizeDefinition.ImageSize, RelativeSource={RelativeSource Mode=Self}}" Value="Small">
                        <Setter Property="FrameworkElement.Height">
                            <Setter.Value>
                                <s:Double>22</s:Double>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="FrameworkElement.Margin" TargetName="PART_Image">
                            <Setter.Value>
                                <Thickness>1,0,1,0</Thickness>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Image.Source" TargetName="PART_Image">
                            <Setter.Value>
                                <Binding Path="SmallImageSource" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="FrameworkElement.Width" TargetName="PART_Image">
                            <Setter.Value>
                                <s:Double>16</s:Double>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="FrameworkElement.Height" TargetName="PART_Image">
                            <Setter.Value>
                                <s:Double>16</s:Double>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="FrameworkElement.HorizontalAlignment" TargetName="TwoLineText">
                            <Setter.Value>
                                <x:Static Member="HorizontalAlignment.Left" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="FrameworkElement.Margin" TargetName="TwoLineText">
                            <Setter.Value>
                                <Thickness>1,1,1,1</Thickness>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="StackPanel.Orientation" TargetName="StackPanel">
                            <Setter.Value>
                                <x:Static Member="Orientation.Horizontal" />
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=ControlSizeDefinition.ImageSize, RelativeSource={RelativeSource Mode=Self}}" Value="Small" />
                            <Condition Binding="{Binding Path=IsInQuickAccessToolBar, RelativeSource={RelativeSource Mode=Self}}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="FrameworkElement.Height">
                            <Setter.Value>
                                <s:Double>NaN</s:Double>
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <DataTrigger Binding="{Binding Path=ControlSizeDefinition.IsLabelVisible, RelativeSource={RelativeSource Mode=Self}}" Value="False">
                        <Setter Property="UIElement.Visibility" TargetName="TwoLineText">
                            <Setter.Value>
                                <x:Static Member="Visibility.Collapsed" />
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=ControlSizeDefinition.ImageSize, RelativeSource={RelativeSource Mode=Self}}" Value="Collapsed">
                        <Setter Property="UIElement.Visibility" TargetName="PART_Image">
                            <Setter.Value>
                                <x:Static Member="Visibility.Collapsed" />
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <Trigger Property="UIElement.IsMouseOver">
                        <Setter Property="Panel.Background" TargetName="OuterBorder">
                            <Setter.Value>
                                <Binding Path="MouseOverBackground" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <Binding Path="MouseOverBorderBrush" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="InnerBorder">
                            <Setter.Value>
                                <SolidColorBrush>#80FFFFFF</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Trigger.Value>
                            <s:Boolean>True</s:Boolean>
                        </Trigger.Value>
                    </Trigger>
                    <Trigger Property="UIElement.IsKeyboardFocused">
                        <Setter Property="Panel.Background" TargetName="OuterBorder">
                            <Setter.Value>
                                <Binding Path="FocusedBackground" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <Binding Path="FocusedBorderBrush" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="InnerBorder">
                            <Setter.Value>
                                <SolidColorBrush>#80FFFFFF</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Trigger.Value>
                            <s:Boolean>True</s:Boolean>
                        </Trigger.Value>
                    </Trigger>
                    <Trigger Property="ButtonBase.IsPressed">
                        <Setter Property="Panel.Background" TargetName="OuterBorder">
                            <Setter.Value>
                                <Binding Path="PressedBackground" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <Binding Path="PressedBorderBrush" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="InnerBorder">
                            <Setter.Value>
                                <SolidColorBrush>#00FFFFFF</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Trigger.Value>
                            <s:Boolean>True</s:Boolean>
                        </Trigger.Value>
                    </Trigger>
                    <Trigger Property="RibbonControlService.IsInControlGroup">
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <Binding Path="Ribbon.BorderBrush" RelativeSource="{RelativeSource Mode=TemplatedParent}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderThickness" TargetName="OuterBorder">
                            <Setter.Value>
                                <Thickness>0,0,1,0</Thickness>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.CornerRadius" TargetName="OuterBorder">
                            <Setter.Value>
                                <CornerRadius>0,0,0,0</CornerRadius>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.CornerRadius" TargetName="InnerBorder">
                            <Setter.Value>
                                <CornerRadius>0,0,0,0</CornerRadius>
                            </Setter.Value>
                        </Setter>
                        <Trigger.Value>
                            <s:Boolean>True</s:Boolean>
                        </Trigger.Value>
                    </Trigger>
                    <Trigger Property="UIElement.IsEnabled">
                        <Setter Property="UIElement.Opacity" TargetName="PART_Image">
                            <Setter.Value>
                                <s:Double>0.5</s:Double>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="TextElement.Foreground" TargetName="OuterBorder">
                            <Setter.Value>
                                <SolidColorBrush>#FF9E9E9E</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Trigger.Value>
                            <s:Boolean>False</s:Boolean>
                        </Trigger.Value>
                    </Trigger>
                    <DataTrigger Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True">
                        <Setter Property="TextElement.Foreground" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.MenuTextBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Panel.Background" TargetName="OuterBorder">
                            <Setter.Value>
                                <SolidColorBrush>#00FFFFFF</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <SolidColorBrush>#00FFFFFF</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.CornerRadius" TargetName="OuterBorder">
                            <Setter.Value>
                                <CornerRadius>0,0,0,0</CornerRadius>
                            </Setter.Value>
                        </Setter>
                    </DataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="True" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.ControlLightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="True" />
                            <Condition Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=Self}}" Value="False" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsDropDownOpen, RelativeSource={RelativeSource Mode=TemplatedParent}, FallbackValue=false}" Value="True" />
                            <Condition Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=Self}}" Value="False" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.ControlLightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsMouseOver, RelativeSource={RelativeSource Mode=Self}}" Value="True" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Panel.Background" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.ControlLightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.CornerRadius" TargetName="OuterBorder">
                            <Setter.Value>
                                <CornerRadius>0,0,0,0</CornerRadius>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="InnerBorder">
                            <Setter.Value>
                                <SolidColorBrush>#00FFFFFF</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="TextElement.Foreground" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsKeyboardFocused, RelativeSource={RelativeSource Mode=Self}}" Value="True" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Panel.Background" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.ControlLightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.CornerRadius" TargetName="OuterBorder">
                            <Setter.Value>
                                <CornerRadius>0,0,0,0</CornerRadius>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="InnerBorder">
                            <Setter.Value>
                                <SolidColorBrush>#00FFFFFF</SolidColorBrush>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="TextElement.Foreground" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsPressed, RelativeSource={RelativeSource Mode=Self}}" Value="True" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Panel.Background" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.HighlightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.ControlDarkBrushKey}" />
                            </Setter.Value>
                        </Setter>
                        <Setter Property="Border.CornerRadius" TargetName="OuterBorder">
                            <Setter.Value>
                                <CornerRadius>0,0,0,0</CornerRadius>
                            </Setter.Value>
                        </Setter>
                        <Setter Property="TextElement.Foreground" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.HighlightTextBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsInControlGroup, RelativeSource={RelativeSource Mode=Self}}" Value="True" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Border.BorderBrush" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.ControlLightLightBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=Self}}" Value="False" />
                            <Condition Binding="{Binding Path=(SystemParameters.HighContrast)}" Value="True" />
                        </MultiDataTrigger.Conditions>
                        <Setter Property="TextElement.Foreground" TargetName="OuterBorder">
                            <Setter.Value>
                                <DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
                            </Setter.Value>
                        </Setter>
                    </MultiDataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
0
votes

Try to use vector graphics. there are allot of tools that you could use to generate a xaml equivalent of this kind of images you can take a look at this article it might help a little.

0
votes

What operating system are you using? - WPF doesn't look as good over XP (not a problem with Vista and 7). I believe that this is due to how the default for anti-aliasing differs between XP and the newer operating systems.

Set the width and height in the XAML to 48 to match the image size (also check the stretch parameter).

With 48x48 32bit PNGs the images should look fine.

Since the ribbon bar is not stretched vector graphics are redundant.

If the above does not help, try setting the align to device pixels and setting the LayoutRounding.

As I suggested in my comment, you could resize the images to the display size, however, it should be set explicitly in the XAML, to make sure that is the same.

You can also get WPF to resize the images explicity by setting the height or width to 32 and using a ScaleTransform.

0
votes

I had the same problem and I created my own usercontrol to solve this.

This is how I did it:

<ribbon:Ribbon>
        <ribbon:RibbonTab Header="File">
            <ribbon:RibbonGroup Header="File">
                <views:ImageButton Command="{Binding LoadCommand}" Caption="Open" SourceImage="/Images/save.png"/>
            </ribbon:RibbonGroup>
        </ribbon:RibbonTab>
    </ribbon:Ribbon>

The image button usercontrol ImageButton.xaml

<UserControl Name="control"

 <Button Command="{Binding Command, ElementName=control}" Style="{x:Null}">
    <StackPanel>
        <infrastructure:AutoGreyableImage Width="32" Source="{Binding SourceImage, ElementName=control}"/>
        <TextBlock Text="{Binding Caption, ElementName=control}"/>
    </StackPanel>
</Button>

The image button usercontrol ImageButton.xaml.cs

public partial class ImageButton : UserControl
{
    public static DependencyProperty CommandProperty = DependencyProperty.Register(
      "Command", typeof(ICommand), typeof(ImageButton));
    public static DependencyProperty SourceProperty = DependencyProperty.Register(
      "SourceImage", typeof(string), typeof(ImageButton));
    public static DependencyProperty CaptionProperty = DependencyProperty.Register(
      "Caption", typeof(string), typeof(ImageButton));

    public ICommand Command
    {
        get
        {
            return (ICommand)GetValue(CommandProperty);
        }
        set
        {
            SetValue(CommandProperty, value);
        }

    }
    public string SourceImage
    {
        get
        {
            return (string)GetValue(SourceProperty);
        }
        set
        {
            SetValue(SourceProperty, value);
        }

    }
    public string Caption
    {
        get
        {
            return (string)GetValue(CaptionProperty);
        }
        set
        {
            SetValue(CaptionProperty, value);
        }

    }
    public ImageButton()
    {
        InitializeComponent();
    }
}

For the AutogreyableImage, I used this post

This is a copy paste of the class

    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;  


/// <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;
                }
            }
        }
    }

I hope this will help you and the others coming