WPF Button use different icon for enabled and disabled state - wpf

How can I give my button different icons depending on the Enabled state. Not very familiar with Style setters yet.
XAML button:
<Button
x:Name="DownloadNewestEpisodes"
Width="90"
Margin="5,5"
ToolTip="Download newest episodes"
ToolTipService.ShowOnDisabled="True"
Command="w:MainWindow.DownloadNewestEpisodesCommand"
CommandParameter="{Binding ElementName=TvShowsTreeView, Path=SelectedItem}">
<StackPanel>
<Image Source="../icons/import.png" />
</StackPanel>
</Button>
How can I switch between
<Image Source="../icons/import.png" />
and
<Image Source="../icons/import_disabled.png" />
based on the enabled state of the button?
A little help would be great!

You can use DataTrigger:
<Button...
>
<StackPanel>
<Image>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" Value="True">
<Setter Property="Source" Value="..." />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}" Value="False">
<Setter Property="Source" Value="..." />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</Button>

Set default image in setter and use DataTrigger to switch to other value (in case IsEnabled set to False):
<Button>
<Image>
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="Images/a.png"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType=Button}}"
Value="False">
<Setter Property="Source" Value="Images/c.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Button>

Related

WPF Load Images Based on Value

I have a List<object> which contains a list of of values for each object which I want to access and create a set image based on the values - don't really want to use a Converter.
I have the below which works:
<Image x:Name="Desk1" Grid.Column="1" Grid.Row="2" Width="50" Height="50">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Office[0].Desks[0].Status} Value="0">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskAvailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Office[0].Desks[0].Status} Value="1">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnavailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Office[0].Desks[0].Status} Value="2">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnknown.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
But I don't want to have to write all this for many desks.
So I've created a Resource:
<Windows.Resources>
<DataTemplate x:Key = "DeskImage">
<Image>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Value="0">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskAvailable.png"/>
</DataTrigger>
<DataTrigger Value="1">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnavailable.png"/>
</DataTrigger>
<DataTrigger Value="2">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnknown.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Windows.Resources>
Which I was hoping to access for each image and just pass it the value in Office[x].Desk[x].Status to determine which image to load. But this is the bit I'm unsure on how to create an image type in xaml and pass the value to the static resource.
Something like:
<Image x:Name="Desk1" Grid.Column="1" Grid.Row="2" Width="50" Height="50">
[pseudocode]
Bind to Office[x].Desks[x].Status
Pass data to Resource and load correct image
[/pseudo]
</image>
You may consider using nested ItemsControls.
<ItemsControl ItemsSource="{Binding Office}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding Desks}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Width="50" Height="50">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="0">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskAvailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="1">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnavailable.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="2">
<Setter Property="Source" Value="pack:///application:,,,/Resources/DeskUnknown.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

'The member "Opacity" is not recognized or is not accessible.' Why can't I set the opacity?

I would like to use a DataTrigger to modify the opacity of my button.
<Button x:Name="StartTreatment"
Grid.Column="3"
Width="160"
Height="30"
Content="{x:Static resources:UserMessages.TrcsConsoleViewModel_LoadWfSequence_StartProcedure}"
IsEnabled="{Binding CanStartProcedure}"
Visibility="{Binding CanStartPatientTreatment, Converter={StaticResource BooleanToVisibility}}" >
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding CanStartProcedure}" Value="False">
<Setter Property="Opacity" Value="0.5"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
I know that a Button has an Opacity you can set, and that DataTriggers must be used in a Style. However the compiler is reporting 'The member "Opacity" is not recognized or is not accessible.' What am I doing wrong?
You should add TargetType:
...
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding CanStartProcedure}" Value="False">
<Setter Property="Opacity" Value="0.5"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
...

WPF RelativeSource issue with nested controls

I have the following markup:
<Button Name="m_SaveButton" Command="{Binding SaveCommand}">
<StackPanel>
<Image Source="{StaticResource IconSave16}">
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}" Value="False">
<Setter Property="Source" Value="{StaticResource IconSaveInactive16}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Label Content="Save" />
</StackPanel>
</Button>
I want to change the Image nested inside the Button when Button.IsEnabled is false. The markup above is not working.
I was trying to use Meleak's code found here: WPF Mouseover Trigger Effect for Child Controls
Does anyone can suggest me a solution for this?
Thank you in advance!
You can't change a local value in style because of Value Precedence. This should work.
<Image>
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="{StaticResource IconSave16}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Button}}}" Value="False">
<Setter Property="Source" Value="{StaticResource IconSaveInactive16}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>

Change Button Image Issue

Im working in WPF and I am trying to change the image of a button, I have created some triggers and Setters, but it is not working.
Here's my XAML code:
<Button BorderThickness="0" Height="23" HorizontalAlignment="Left" Margin="59,6,0,0" Name="topButton" Width="26" VerticalAlignment="Top"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" IsEnabled="False" >
<StackPanel>
<Image>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=topButton, Path=Button.IsEnabled}" Value="True">
<Setter Property="Image.Source" Value="Images/MoveFirst_Enabled.bmp" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=topButton, Path=Button.IsEnabled}" Value="False">
<Setter Property="Image.Source" Value="Images/MoveFirst_Disabled.bmp" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</Button>
I cant realize what I am doing wrong. Hope you can help me. Thank you in advance.
Remove the Button. for the Path. So instead of
Path=Button.IsEnabled
you should have
Path=IsEnabled
Example
<Button BorderThickness="0" Height="23" HorizontalAlignment="Left" Margin="59,6,0,0" Name="topButton" Width="26" VerticalAlignment="Top" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" IsEnabled="False">
<StackPanel>
<Image>
<Image.Style>
<Style TargetType="Image">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=topButton, Path=IsEnabled}" Value="True">
<Setter Property="Source" Value="Images/MoveFirst_Enabled.bmp" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=topButton, Path=IsEnabled}" Value="False">
<Setter Property="Source" Value="Images/MoveFirst_Disabled.bmp" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</Button>
I think you are not using the correct Uri string for the Source of the Image.
<Button BorderThickness="0" Height="23" HorizontalAlignment="Left" Margin="59,6,0,0" Name="topButton" Width="26" VerticalAlignment="Top"
Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" IsEnabled="False" >
<StackPanel>
<Image>
<Image.Style>
<Style TargetType="Image">
<!-- If you are using the Image as a Resource, you should use the following format.-->
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=topButton, Path=Button.IsEnabled}" Value="True">
<Setter Property="Image.Source" Value="assemblyname;component/Images/MoveFirst_Enabled.bmp" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=topButton, Path=Button.IsEnabled}" Value="False">
<Setter Property="Image.Source" Value="assemblyname;component/Images/MoveFirst_Disabled.bmp" />
</DataTrigger>
</Style.Triggers>
<!-- If you are using the Image as Content then you should use the below format.-->
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=topButton, Path=Button.IsEnabled}" Value="True">
<Setter Property="Image.Source" Value="Images/MoveFirst_Enabled.bmp" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=topButton, Path=Button.IsEnabled}" Value="False">
<Setter Property="Image.Source" Value="Images/MoveFirst_Disabled.bmp" />
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</StackPanel>
</Button>
I hope it may help you...

Changing Button image when IsEnabled

I want to change button image when button IsEnabled == False.
Below is my example, bindings are fine, when I change them for False/True it is still not working.
<Button x:Name="btnBackward" Grid.Column="0" Grid.Row="2" Command="{Binding UserWorkflowManager.NavigateBackward}" IsEnabled="{Binding UserWorkflowManager.NavigateBackwardEnable}" Grid.RowSpan="2">
<Button.Template>
<ControlTemplate>
<Image Name="_image" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="Uniform">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="/UserWorkflow.View;component/Images/LDC500_butX_PreviousPane_norm.bmp" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=btnBackward, Path=IsEnabled}" Value="False">
<Setter Property="Source" Value="/UserWorkflow.View;component/Images/LDC500_butX_PreviousPane_dis.bmp"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</ControlTemplate>
</Button.Template>
</Button>
Try the following
<Style.Triggers>
<DataTrigger Binding="{Binding IsEnabled,RelativeSource={RelativeSource AncestorType=Button}}" Value="False">
<Setter Property="Source" Value="/UserWorkflow.View;component/Images/LDC500_butX_PreviousPane_dis.bmp"/>
</DataTrigger>
</Style.Triggers>
Or add the trigger directly in the control template like so
<ControlTemplate>
<Image Name="_image" HorizontalAlignment="Center">
..........
</Image>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="_image" Property="Source" Value="/UserWorkflow.View;component/Images/LDC500_butX_PreviousPane_dis.bmp" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
Try this:
<Button x:Name="btnBackward" Grid.Column="0" Click="btnBackward_Click">
<Button.Template>
<ControlTemplate>
<Image Name="_image" HorizontalAlignment="Center" VerticalAlignment="Center" Stretch="Uniform">
<Image.Style>
<Style TargetType="Image">
<Setter Property="Source" Value="/Images/0.png" />
</Style>
</Image.Style>
</Image>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Source" Value="/Images/1.png" TargetName="_image"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
You should specify "TargetName" property for a setter within "ControlTemplate.Triggers"
The soution is is to use RelativeSource={RelativeSource Self}} in your DataTrigger.
<DataTrigger
Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}}"
Value="False">
Example
Add this style:
<Style x:Key="MainButtonStyle" TargetType="Button" BasedOn="{StaticResource ChromelessButtonStyle}">
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource Self}}" Value="False">
<Setter Property="Background" Value="Blue" />
</DataTrigger>
</Style.Triggers>
</Style>
Then apply this style to the button:
<Button x:Name="ActionButton" Style="{StaticResource MainButtonStyle}" Command="{Binding MyCmd}" IsEnabled="{Binding ActionButtonEnabled}"/>

Resources