21

当按钮被禁用时,我想使我的图像(在按钮上)变灰。当我在按钮上有文本(无图像)时,文本显示为灰色(图像作为按钮内容,它们不会显示为灰色)。有没有简单又漂亮的方法来做到这一点?

这是我的 xaml 文件:

<Window x:Class="WpfApplication2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <ToolBarTray VerticalAlignment="Top" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" IsLocked="true" Grid.Row="0">
            <ToolBar Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Band="1" BandIndex="1">
                <Button Command="{Binding Button1}" RenderOptions.BitmapScalingMode="NearestNeighbor">
                    <Button.Content>
                        <Image Source="open.ico"></Image>
                    </Button.Content>
                </Button>
                <Button Command="{Binding Button2}" RenderOptions.BitmapScalingMode="NearestNeighbor">
                    <Button.Content>
                        <Image Source="open.ico"></Image>
                    </Button.Content>
                </Button>
            </ToolBar>
        </ToolBarTray>
    </Grid>
</Window>

这是我的文件后面的代码:

public partial class MainWindow : Window
{
    private RelayCommand _button1;
    private RelayCommand _button2;

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
    }

    public ICommand Button1
    {
        get
        {
            if (_button1 == null)
            {
                _button1 = new RelayCommand(Button1E, Button1C);
            }
            return _button1;
        }
    }

    public ICommand Button2
    {
        get
        {
            if (_button2 == null)
            {
                _button2 = new RelayCommand(Button2E, Button2C);
            }
            return _button2;
        }
    }

    public void Button1E(object parameter)
    {
        Trace.WriteLine("Button 1");
    }

    public bool Button1C(object parameter)
    {
        return true;
    }

    public void Button2E(object parameter)
    {
        Trace.WriteLine("Button 2");
    }

    public bool Button2C(object parameter)
    {
        return false;
    }
}
4

5 回答 5

18

As Thomas Lebrun says in his post How to gray the icon of a MenuItem ? the best way at the moment is probably to create a little class, AutoGreyableImage, which allow you to have an image that will be turn in gray automatically when the control is deactivated.

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:

Result of applying class to perform grayscale rendering when disabled

Sources

于 2012-07-06T06:19:37.400 回答
6

您可以使用像素着色器自动执行此操作。

于 2012-07-03T08:15:16.717 回答
4

或通过附加属性相同。

<Image behaviors:GrayoutImageBehavior.GrayOutOnDisabled="True" Source="/WpfApp;component/Resources/picture.png" />

灰度图像行为:

public class GrayoutImageBehavior
{
    public static readonly DependencyProperty GrayOutOnDisabledProperty = DependencyProperty.RegisterAttached("GrayOutOnDisabled", typeof(bool), typeof(GrayoutImageBehavior), new PropertyMetadata(default(bool), OnGrayOutOnDisabledChanged));
    public static void SetGrayOutOnDisabled(Image element, bool value) { element.SetValue(GrayOutOnDisabledProperty, value); }
    public static bool GetGrayOutOnDisabled(Image element) { return (bool)element.GetValue(GrayOutOnDisabledProperty); }

    private static void OnGrayOutOnDisabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        Image image = (Image) obj;
        image.IsEnabledChanged -= OnImageIsEnabledChanged;

        if ((bool)args.NewValue)
            image.IsEnabledChanged += OnImageIsEnabledChanged;

        ToggleGrayOut(image); // initial call
    }

    private static void OnImageIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var image = (Image)sender;
        ToggleGrayOut(image);
    }

    private static void ToggleGrayOut(Image image)
    {
        try
        {
            if (image.IsEnabled)
            {
                var grayImage = image.Source as FormatConvertedBitmap;
                if (grayImage != null)
                {
                    image.Source = grayImage.Source; // Set the Source property to the original value.
                    image.OpacityMask = null; // Reset the Opacity Mask
                    image.Opacity = 1.0;
                }
            }
            else
            {
                var bitmapImage = default(BitmapImage);

                if (image.Source is BitmapImage)
                    bitmapImage = (BitmapImage) image.Source;
                else if (image.Source is BitmapSource) // assume uri source
                    bitmapImage = new BitmapImage(new Uri(image.Source.ToString()));

                if (bitmapImage != null)
                {
                    image.Source = new FormatConvertedBitmap(bitmapImage, PixelFormats.Gray32Float, null, 0); // Get the source bitmap
                    image.OpacityMask = new ImageBrush(bitmapImage); // Create Opacity Mask for grayscale image as FormatConvertedBitmap does not keep transparency info
                    image.Opacity = 0.3; // optional: lower opacity
                }
            }
        }
        catch (Exception ex)
        {
            LogicLogger.WriteLogEntry("Converting image to grayscale failed", LogLevel.Debug, false, ex);
        }
    }
}
于 2014-08-26T17:16:01.570 回答
3

Thomas Lebrun的 AutoGreyableImage 的更完整版本。对于任何有兴趣的人,我开始使用 Thomas Lebruns 类并遇到了几个空引用异常,并且发现如果先设置 isEnabled 属性然后再设置源,则不会禁用图像。

所以这是最终为我成功的课程。À 建议,您当然可以在其中添加不透明度问题,但我决定将其留给图像周围的 xaml。

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

namespace MyDisabledImages
{
    /// <summary>
    /// Class used to have an image that is able to be gray when the control is not enabled.
    /// Based on the version by 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 and Source property.
            IsEnabledProperty.OverrideMetadata(typeof(AutoGreyableImage), new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnAutoGreyScaleImageIsEnabledPropertyChanged)));
            SourceProperty.OverrideMetadata(typeof(AutoGreyableImage), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnAutoGreyScaleImageSourcePropertyChanged)));
        }

        protected static AutoGreyableImage GetImageWithSource(DependencyObject source)
        {
            var image = source as AutoGreyableImage;
            if (image == null)
                return null;

            if (image.Source == null)
                return null;

            return image;
        }

        /// <summary>
        /// Called when [auto grey scale image source property changed].
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="args">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        protected static void OnAutoGreyScaleImageSourcePropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs ars)
        {
            AutoGreyableImage image = GetImageWithSource(source);
            if (image != null)
                ApplyGreyScaleImage(image, image.IsEnabled);
        }

        /// <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>
        protected static void OnAutoGreyScaleImageIsEnabledPropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs args)
        {
            AutoGreyableImage image = GetImageWithSource(source);
            if (image != null)
            {
                var isEnabled = Convert.ToBoolean(args.NewValue);
                ApplyGreyScaleImage(image, isEnabled);
            }
        }

        protected static void ApplyGreyScaleImage(AutoGreyableImage autoGreyScaleImg, Boolean isEnabled)
        {
            try
            {
                if (!isEnabled)
                {
                    BitmapSource bitmapImage = null;

                    if (autoGreyScaleImg.Source is FormatConvertedBitmap)
                    {
                        // Already grey !
                        return;
                    }
                    else if (autoGreyScaleImg.Source is BitmapSource)
                    {
                        bitmapImage = (BitmapSource)autoGreyScaleImg.Source;
                    }
                    else // trying string 
                    {
                        bitmapImage = new BitmapImage(new Uri(autoGreyScaleImg.Source.ToString()));
                    }
                    FormatConvertedBitmap conv = new FormatConvertedBitmap(bitmapImage, PixelFormats.Gray32Float, null, 0);
                    autoGreyScaleImg.Source = conv;

                    // Create Opacity Mask for greyscale image as FormatConvertedBitmap does not keep transparency info
                    autoGreyScaleImg.OpacityMask = new ImageBrush(((FormatConvertedBitmap)autoGreyScaleImg.Source).Source); //equivalent to new ImageBrush(bitmapImage)
                }
                else
                {
                    if (autoGreyScaleImg.Source is FormatConvertedBitmap)
                    {
                        autoGreyScaleImg.Source = ((FormatConvertedBitmap)autoGreyScaleImg.Source).Source;
                    }
                    else if (autoGreyScaleImg.Source is BitmapSource)
                    {
                        // Should be full color already.
                        return;
                    }

                    // Reset the Opcity Mask
                    autoGreyScaleImg.OpacityMask = null;
                }
            }
            catch (Exception)
            {
                // nothin'
            }

        }

    }
}
于 2014-07-01T13:50:53.523 回答
3

我已经更改了 GrayoutImageBehavior,这样就不会有灰色图像的内存泄漏,这是当用户将图像“启用”属性从 true 更改为 false 时引起的,反之亦然。我添加了 DependencyProperty 来保存灰色图像和灰色图像不透明蒙版。

 public class GrayoutImageBehavior
 {
     public static readonly DependencyProperty GrayOutOnDisabledProperty = DependencyProperty.RegisterAttached("GrayOutOnDisabled", typeof(bool), typeof(GrayoutImageBehavior), new PropertyMetadata(default(bool), OnGrayOutOnDisabledChanged));
     public static void SetGrayOutOnDisabled(Image element, bool value) { element.SetValue(GrayOutOnDisabledProperty, value); }
     public static bool GetGrayOutOnDisabled(Image element) { return (bool)element.GetValue(GrayOutOnDisabledProperty); }

     private static DependencyProperty GrayImageProperty = DependencyProperty.RegisterAttached("GrayImage", typeof(FormatConvertedBitmap), typeof(GrayoutImageBehavior));
     private static void SetGrayImage(Image element, FormatConvertedBitmap value) { element.SetValue(GrayImageProperty, value); }
     private static FormatConvertedBitmap GetGrayImage(Image element) { return (FormatConvertedBitmap)element.GetValue(GrayImageProperty); }

     private static DependencyProperty GrayImageOpacityMaskProperty = DependencyProperty.RegisterAttached("GrayImageOpacityMask", typeof(Brush), typeof(GrayoutImageBehavior));
     private static void SetGrayImageOpacityMask(Image element, Brush value) { element.SetValue(GrayImageOpacityMaskProperty, value); }
     private static Brush GetGrayImageOpacityMask(Image element) { return (Brush)element.GetValue(GrayImageOpacityMaskProperty); }

     private static void OnGrayOutOnDisabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
     {
         Image image = (Image)obj;
         image.IsEnabledChanged -= OnImageIsEnabledChanged;

         if ((bool)args.NewValue)
             image.IsEnabledChanged += OnImageIsEnabledChanged;

         ToggleGrayOut(image); // initial call
     }

     private static void OnImageIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs args)
     {
         var image = (Image)sender;
         ToggleGrayOut(image);
     }

     private static void ToggleGrayOut(Image image)
     {
         try
         {
             if (image.IsEnabled)
             {
                 var grayImage = image.Source as FormatConvertedBitmap;
                 if (grayImage != null)
                 {
                     image.Source = grayImage.Source; // Set the Source property to the original value.
                     image.OpacityMask = null; // Reset the Opacity Mask
                     //image.Opacity = 1.0;
                 }
             }
             else
             {
                 FormatConvertedBitmap grayImage = GetGrayImage(image);
                 Brush grayOpacityMask = GetGrayImageOpacityMask(image);

                 if(grayImage == null)
                 {
                     var bitmapImage = default(BitmapImage);

                     if (image.Source is BitmapImage)
                         bitmapImage = (BitmapImage)image.Source;
                     else if (image.Source is BitmapSource) // assume uri source
                         bitmapImage = new BitmapImage(new Uri(image.Source.ToString()));

                     if (bitmapImage != null)
                     {
                         grayImage = new FormatConvertedBitmap(bitmapImage, PixelFormats.Gray32Float, null, 0); // Get the source bitmap
                         SetGrayImage(image, grayImage);
                         grayOpacityMask = new ImageBrush(bitmapImage); // Create Opacity Mask for grayscale image as FormatConvertedBitmap does not keep transparency info
                         SetGrayImageOpacityMask(image, grayOpacityMask);
                         //image.Opacity = 0.3; // optional: lower opacity
                     }
                 }

                 image.Source = grayImage;
                 image.OpacityMask = grayOpacityMask;
             }
         }
         catch (Exception ex)
         {
             //LogicLogger.WriteLogEntry("Converting image to grayscale failed", LogLevel.Debug, false, ex);
         }
     }
 }
于 2016-12-06T06:07:03.650 回答