2012-07-03 31 views
19

Quiero atenuar mis imágenes (en los botones) cuando los botones están deshabilitados. Cuando tengo texto (sin imágenes) en el botón, el texto aparece atenuado (con las imágenes como Contenido del botón, no aparecen grises). ¿Hay alguna manera simple y hermosa de hacer eso?Imagen gris en el botón cuando el elemento está desactivado (forma simple y hermosa)

Este es mi archivo 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> 

y esto es mi código detrás de archivo:

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; 
    } 
} 
+1

No veo ningún intento de abordar el problema en el código – Alex

Respuesta

16

Como dice Thomas Lebrun en su publicación How to gray the icon of a MenuItem ?, la mejor manera en este momento es crear una pequeña clase, AutoGreyableImage, que le permita tener una imagen que se volverá gris automáticamente cuando se desactive el control.

Aquí es cómo se puede usar:

<MenuItem Header="Edit"> 
    <MenuItem x:Name="miPaste" 
              Header="Paste"> 
        <MenuItem.Icon> 
            <local:AutoGreyableImage Source="pack://application:,,,/Images/Paste.png" 
                                                   /> 
        </MenuItem.Icon> 
    </MenuItem> 
</MenuItem> 
  

Y aquí es la implementación:

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

aquí está el resultado:

Result of applying class to perform grayscale rendering when disabled

Sources

+0

¿Enlace muerto? Me tomé la molestia de registrarme en el foro y responder preguntas ridículas sobre robots en francés, y se muestra una página en blanco. ¡No es justo! –

+0

@IvanKrivyakov He actualizado el enlace muerto al artículo original. – David

+1

Eso funcionó. Merci! Gracias por la respuesta rápida. Aunque sería bueno si por el bien de otras personas lo pones en un lugar más accesible, como DropBox o Github.La mayoría de los programadores de WPF no saben francés y tendrán dificultades para registrarse en developpez.net. –

4

Se podría use a pixel shader hacer esto de forma automática.

+0

nice one, ¡No sabía acerca de este efecto! Ojalá hubiera leído eso hace 2 años: p – David

3

Versión más completa de AutoGreyableImage por Thomas Lebrun. Para cualquier persona interesada, comencé a usar la clase de Thomas Lebruns y encontré un par de excepciones de nullreferences, así como también descubrí que una imagen no se desactivaría si la propiedad isEnabled se estableció primero y la fuente se configuró después.

Así que aquí está la clase que finalmente me dio el truco. A propos, por supuesto puede agregar el asunto de la opacidad a esto, pero decidí dejar eso hasta la xaml alrededor de la imagen.

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' 
      } 

     } 

    } 
} 
3

O el mismo en la propiedad adjunta.

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

GrayoutImageBehavior:

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); 
     } 
    } 
} 
1

he cambiado GrayoutImageBehavior de manera que no habrá pérdidas de memoria de la imagen gris, causada cuando el usuario cambia la imagen 'enable' propiedad de verdadero a falso y viceversa varias veces. He agregado DependencyProperty para contener la imagen gris y la máscara de opacidad de la imagen gris.

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); 
     } 
    } 
} 
Cuestiones relacionadas