Michael D.
Michael D.

Reputation: 1319

ImageButton: image is not displayed when button disabled

I have created an UserControl to implement a simple ImageButton as following:

<UserControl x:Class="MyApp.Common.Controls.ImageButton"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Name="UC">
<Grid>
    <Button Command="{Binding ElementName=UC, Path=Command}" CommandParameter="{Binding ElementName=UC, Path=CommandParameter}">
        <StackPanel Orientation="Horizontal">
            <Image Source="{Binding ElementName=UC, Path=Image}"
                   Width="{Binding ElementName=UC, Path=ImageWidth}"
                   Height="{Binding ElementName=UC, Path=ImageHeight}"/>
            <TextBlock Text="{Binding ElementName=UC, Path=Text}"  />
        </StackPanel>
    </Button>
</Grid>

Here is code-behind of my control:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

namespace MyApp.Common.Controls
{
    public partial class ImageButton : UserControl
    {
        public ImageButton()
        {
            InitializeComponent();
        }

        public ImageSource Image
        {
            get { return (ImageSource)GetValue(ImageProperty); }
            set { SetValue(ImageProperty, value); }
        }

        public static readonly DependencyProperty ImageProperty =
            DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));

        public double ImageWidth
        {
            get { return (double)GetValue(ImageWidthProperty); }
            set { SetValue(ImageWidthProperty, value); }
        }

        public static readonly DependencyProperty ImageWidthProperty =
            DependencyProperty.Register("ImageWidth", typeof(double), typeof(ImageButton), new UIPropertyMetadata(16d));


        public double ImageHeight
        {
            get { return (double)GetValue(ImageHeightProperty); }
            set { SetValue(ImageHeightProperty, value); }
        }

        public static readonly DependencyProperty ImageHeightProperty =
            DependencyProperty.Register("ImageHeight", typeof(double), typeof(ImageButton), new UIPropertyMetadata(16d));


        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(string), typeof(ImageButton), new UIPropertyMetadata(""));

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

        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.Register("Command", typeof(ICommand), typeof(ImageButton));



        public object CommandParameter
        {
            get { return GetValue(CommandParameterProperty); }
            set { SetValue(CommandParameterProperty, value); }
        }

        public static readonly DependencyProperty CommandParameterProperty =
            DependencyProperty.Register("CommandParameter", typeof(object), typeof(ImageButton));
    }
}

The usage is simple:

            <cc:ImageButton Command="{Binding SearchCommand}" 
                Image="/MyApp;component/Images/magnifier.png"       
                ImageWidth="16" ImageHeight="16"        
                        />

When the button (bound to DelegateCommand in my ViewModel) get disabled the image is disappear. Otherwise all works as expected. What could be a problem? How to make the image show in gray-scale when disabled?

UPDATE: here is the image of this strange behaviorscreenshot:

Upvotes: 0

Views: 862

Answers (3)

VladimirBadiuk
VladimirBadiuk

Reputation: 21

I would make it custom control,make a trigger for it at Property =isEnabled value=false. Over the image,I would add a grid with some opacity,and control that opacity or visibility with that trigger. Good luck. I don't think there is an easier way.

Upvotes: 0

Sebastian Edelmeier
Sebastian Edelmeier

Reputation: 4167

As mentioned before, there is no built-in desaturation support in WPF, but you can easily use a shader effect to implement that. The link takes you to an implementation that lets you use the effect in a XAML-only way.

Please note that for shaders written in HLSL need to be compiled and for compilation you will need the Direct X SDK installed on your machine. Quite a beast for such a small task, admitted.

Upvotes: 0

shanewwarren
shanewwarren

Reputation: 2294

I copied the code that you had provided to see if I could reproduce the problem you were having. Unfortunately, when the command was disabled (or it's CanExecute was returning false) the image I used did not disappear. Could you please provide more code from your ViewModel that you think may be relevant?

To answer the second part of your question:

How to make the image show in gray-scale when disabled?

As far as I know there is no easy way to desaturate an image in WPF. Instead, I would go with the approach that @Vova had suggested which is to lower the Opacity property of the Image. You can modify your UserControl XAML you provided like so:

<UserControl x:Class="MyApp.Common.Controls.ImageButton"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Name="UC">
    <Grid>
        <Button Command="{Binding ElementName=UC, Path=Command}" CommandParameter="{Binding ElementName=UC, Path=CommandParameter}">

            <StackPanel Orientation="Horizontal">
                <Image Source="{Binding ElementName=UC, Path=Image}"
                   Width="{Binding ElementName=UC, Path=ImageWidth}"
                   Height="{Binding ElementName=UC, Path=ImageHeight}">
                    <Image.Style>
                        <Style TargetType="{x:Type Image}">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding  Path=IsEnabled, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}} }" Value="false"  >
                                    <Setter Property="Opacity" Value="0.3" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Image.Style>
                </Image>
                <TextBlock Text="{Binding ElementName=UC, Path=Text}"  />
            </StackPanel>
        </Button>
    </Grid>
</UserControl>

In the code above I added a DataTrigger to the Image's Style property to modify the opacity of the image if the IsEnabled property of the button is equal to false.

Hope this helps!

Upvotes: 1

Related Questions