如何使WPF图像失效?

时间:2021-07-03 20:47:19

I need an Image that is grayed out when disabled (IsEnabled=False). A grayed out version of the image can be produced by reading the BitmapImage into a FormatConvertedBitmap which is shown here.

当禁用(IsEnabled=False)时,我需要一个灰色的图像。通过将位图图像读入一个格式转换的位图(此处显示),可以生成图像的灰色版本。

I have been able to get this working with a UserControl but now I would like the same behavior in a specialized Image class for more flexibility. I don't care if this is implemented in XAML, code-behind or both, but it needs to be a subclass of Image.

我已经能够在UserControl中使用它,但是现在我希望在专门化的Image类中使用相同的行为,以获得更大的灵活性。我不关心它是在XAML中实现的,代码隐藏的还是两者都实现的,但是它需要是Image的子类。

The usage could be:

使用可以:

<DisableableImage Source="Images/image1.png" />
<DisableableImage Source="Images/image1.png" IsEnabled="False" />

<!-- Since IsEnabled is inherited down the tree,
     the image will be grayed out like the rest of the button -->
<Button IsEnabled="False">
    <StackPanel Orientation="Horizontal">
        <TextBlock>OK</TextBlock>
        <DisableableImage Source="Images/ok.png" />
    </StackPanel>
</Button>

5 个解决方案

#1


9  

Have a look at this link

看看这个链接

EDIT: Or this one (all you need is the AutoGreyableImage class)

编辑:或者这个(你只需要AutoGreyableImage类)

#2


5  

I made a little comparison based on the following solutions.

基于下面的解决方案,我做了一些比较。

  • The approaches in the link provided by the OP
  • OP提供的链接中的方法。
  • The links provided by Thomas Levesque
  • 由Thomas Levesque AutoDisabledImage AutoGreyableImage提供的链接
  • Greyscale Effect
  • 灰度的影响

Since I already had a licens for the Infragistics Net Advantage for WPF it was easy to try it out

由于我已经获得了WPF的次特性优势的许可,所以很容易尝试

Here is the result

这是结果

如何使WPF图像失效?

So the best approach depends on what results you are after. As for me, I think the result produced by AutoDisabledImage from Infragistics is too bright, AutoGreyableImage does a pretty good job (Identical result to Approach 1 (OP link)) and GreyscaleEffect produces the best result.

所以最好的方法取决于你想要什么结果。对于我来说,我认为从红外的角度来看,AutoDisabledImage的结果是太亮了,AutoGreyableImage做的很好(接近1 (OP link))和GreyscaleEffect产生了最好的结果。

#3


2  

if you use this a lot consider creating a custom Effect introduced with .NET 3.5 SP1 (not bitmapeffect) to render such an operation on your GPU. this effect can then be easily controlled by triggers.

如果您经常使用它,请考虑使用。net 3.5 SP1(而不是bitmapeffect)创建一个自定义效果,以便在GPU上呈现这样的操作。这种效应可以很容易被触发器控制。

#4


2  

More complete version of the AutoGreyableImage by Thomas Lebrun. For anyone interested, I started using Thomas Lebruns class and ran into a couple of nullreference exceptions, as well as finding out that an image would not be disabled if the isEnabled property was set first and the source set after.

托马斯·莱布伦(Thomas Lebrun)更为完整的自动灰度图像。对于任何感兴趣的人,我开始使用Thomas Lebruns类并遇到了两个nullreference异常,并发现如果首先设置isEnabled属性,然后设置源属性,则不会禁用映像。

So here's the class that finally did the trick for me. À propos, you can of course add the matter of opacity into this, but I decided to leave that up to the xaml around the image.

这门课终于帮了我的忙。顺便说一下,你当然可以把不透明度添加进去,但是我决定把它放在图像周围的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'
            }

        }

    }
}

#5


0  

Create a DisableableImage class that is a typical WPF control. Inside, place two elements: the image, and a rectangle that appears only when the control is disabled. The rectangle should be the same width and height as the image, and it should overlay the image. With a color of gray and an alpha of somewhere around 40%, you should get an effect similar to actually graying out the image -- without all the effort to actually modify the image itself.

创建一个DisableableImage类,它是一个典型的WPF控件。在内部,放置两个元素:图像和仅在禁用控件时出现的矩形。矩形的宽度和高度应与图像相同,并应覆盖图像。如果颜色是灰色的,alpha值在40%左右,你应该会得到一种效果,类似于把图像变灰——而不需要真正修改图像本身。

#1


9  

Have a look at this link

看看这个链接

EDIT: Or this one (all you need is the AutoGreyableImage class)

编辑:或者这个(你只需要AutoGreyableImage类)

#2


5  

I made a little comparison based on the following solutions.

基于下面的解决方案,我做了一些比较。

  • The approaches in the link provided by the OP
  • OP提供的链接中的方法。
  • The links provided by Thomas Levesque
  • 由Thomas Levesque AutoDisabledImage AutoGreyableImage提供的链接
  • Greyscale Effect
  • 灰度的影响

Since I already had a licens for the Infragistics Net Advantage for WPF it was easy to try it out

由于我已经获得了WPF的次特性优势的许可,所以很容易尝试

Here is the result

这是结果

如何使WPF图像失效?

So the best approach depends on what results you are after. As for me, I think the result produced by AutoDisabledImage from Infragistics is too bright, AutoGreyableImage does a pretty good job (Identical result to Approach 1 (OP link)) and GreyscaleEffect produces the best result.

所以最好的方法取决于你想要什么结果。对于我来说,我认为从红外的角度来看,AutoDisabledImage的结果是太亮了,AutoGreyableImage做的很好(接近1 (OP link))和GreyscaleEffect产生了最好的结果。

#3


2  

if you use this a lot consider creating a custom Effect introduced with .NET 3.5 SP1 (not bitmapeffect) to render such an operation on your GPU. this effect can then be easily controlled by triggers.

如果您经常使用它,请考虑使用。net 3.5 SP1(而不是bitmapeffect)创建一个自定义效果,以便在GPU上呈现这样的操作。这种效应可以很容易被触发器控制。

#4


2  

More complete version of the AutoGreyableImage by Thomas Lebrun. For anyone interested, I started using Thomas Lebruns class and ran into a couple of nullreference exceptions, as well as finding out that an image would not be disabled if the isEnabled property was set first and the source set after.

托马斯·莱布伦(Thomas Lebrun)更为完整的自动灰度图像。对于任何感兴趣的人,我开始使用Thomas Lebruns类并遇到了两个nullreference异常,并发现如果首先设置isEnabled属性,然后设置源属性,则不会禁用映像。

So here's the class that finally did the trick for me. À propos, you can of course add the matter of opacity into this, but I decided to leave that up to the xaml around the image.

这门课终于帮了我的忙。顺便说一下,你当然可以把不透明度添加进去,但是我决定把它放在图像周围的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'
            }

        }

    }
}

#5


0  

Create a DisableableImage class that is a typical WPF control. Inside, place two elements: the image, and a rectangle that appears only when the control is disabled. The rectangle should be the same width and height as the image, and it should overlay the image. With a color of gray and an alpha of somewhere around 40%, you should get an effect similar to actually graying out the image -- without all the effort to actually modify the image itself.

创建一个DisableableImage类,它是一个典型的WPF控件。在内部,放置两个元素:图像和仅在禁用控件时出现的矩形。矩形的宽度和高度应与图像相同,并应覆盖图像。如果颜色是灰色的,alpha值在40%左右,你应该会得到一种效果,类似于把图像变灰——而不需要真正修改图像本身。