2012-07-03 37 views
19

Tôi muốn tô xám hình ảnh của mình (trên các nút) khi các nút bị tắt. Khi tôi có văn bản (không có hình ảnh) trên nút, văn bản được chuyển sang màu xám (Với Hình ảnh là Nội dung Nút, chúng không có màu xám). Có cách nào đơn giản và đẹp để làm điều đó không?Xám ra hình ảnh trên nút khi phần tử bị tắt (đơn giản và đẹp)

Đây là tập tin XAML của tôi:

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

và đây là mã của tôi đằng sau file:

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

Tôi không thấy bất kỳ nỗ lực nào trong việc giải quyết vấn đề trong mã – Alex

Trả lời

16

Như Thomas Lebrun nói trong bài viết của mình How to gray the icon of a MenuItem ? cách tốt nhất vào lúc này có lẽ là tạo một lớp nhỏ, AutoGreyableImage, cho phép bạn có một hình ảnh sẽ tự động chuyển sang màu xám khi điều khiển bị vô hiệu hóa.

Đây là cách bạn có thể sử dụng nó:

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

Và đây là việc thực hiệ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; 
            } 
        } 
    } 
} 
  

Dưới đây là kết quả:

Result of applying class to perform grayscale rendering when disabled

Sources

+0

Liên kết chết? Tôi đã gặp rắc rối khi đăng ký diễn đàn và trả lời các câu hỏi chống rô-bốt vô lý bằng tiếng Pháp, và nó hiển thị là một trang trống. Không đẹp! –

+0

@IvanKrivyakov Tôi đã cập nhật liên kết đã chết đến bài viết gốc. – David

+1

Điều đó đã hiệu quả. Merci! Cảm ơn bạn đã trả lời nhanh. Nó sẽ được tốt đẹp mặc dù nếu vì lợi ích của người khác bạn đặt nó ở một nơi nào đó dễ tiếp cận hơn, như DropBox, hoặc github.Hầu hết các lập trình WPF không biết tiếng Pháp và sẽ gặp khó khăn khi đăng ký developpez.net. –

4

Bạn có thể use a pixel shader để làm điều này tự động.

+0

tốt nhất, tôi không biết về hiệu ứng này! Tôi ước tôi đã đọc 2 năm trước: p – David

3

Phiên bản hoàn chỉnh khác của AutoGreyableImage theo số Thomas Lebrun. Đối với bất cứ ai quan tâm, tôi bắt đầu sử dụng lớp Thomas Lebruns và chạy vào một vài ngoại lệ nullreference, cũng như phát hiện ra rằng một hình ảnh sẽ không bị vô hiệu hóa nếu thuộc tính isEnabled được đặt đầu tiên và nguồn được đặt sau.

Vì vậy, đây là lớp cuối cùng đã thực hiện thủ thuật cho tôi. À đề nghị, tất nhiên bạn có thể thêm vấn đề về độ mờ đục vào điều này, nhưng tôi đã quyết định để nó lại với xaml xung quanh hình ảnh.

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

Hoặc tương tự bằng thuộc tính đính kèm.

<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

Tôi đã thay đổi GrayoutImageBehavior để sẽ không có rò rỉ bộ nhớ của hình ảnh màu xám, xảy ra khi người dùng thay đổi hình ảnh 'cho phép' bất động sản từ true sang false và ngược lại nhiều lần. Tôi đã thêm DependencyProperty để giữ hình ảnh màu xám và mặt nạ mờ hình ảnh màu xám.

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); 
     } 
    } 
} 
Các vấn đề liên quan