WPF RelativeSource issue with nested controls - wpf

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>

Related

WPF Button use different icon for enabled and disabled state

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>

Devexpress( WPF GridControl) modify image inside a GridColumn using DataTrigger

I am using a WPF Devexpress GridControl and I have a column that contains an image. I want to modify the Image using a DataTrigger. Here is the XAML:
<dxg:GridColumn Header="{Binding Source={StaticResource MainWindowResources}, Path=Resource.Status}"
FieldName="SaveStatus"
MinWidth="60"
Width="60"
ReadOnly="True"
>
<dxg:GridColumn.CellTemplate>
<DataTemplate>
<Image HorizontalAlignment="Center"
VerticalAlignment="Center"
Style="{StaticResource ImageStatusStyle}">
</Image>
</DataTemplate>
</dxg:GridColumn.CellTemplate>
</dxg:GridColumn>
and the style:
<Style TargetType="{x:Type Image}" x:Key="ImageStatusStyle">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Data.SaveStatus, UpdateSourceTrigger=
PropertyChanged}" Value="{x:Static enums:SaveState.DoneSuccesfuly}">
<Setter Property="Source" Value="..\Icons\StatusOk.png" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Data.SaveStatus, UpdateSourceTrigger=
PropertyChanged}" Value="{x:Static enums:SaveState.DoneUnsuccesfuly}">
<Setter Property="Source" Value="..\Icons\StatusError.png" />
</DataTrigger>
</Style.Triggers>
</Style>
This doesn't work. What am I doing wrong? Is there a better solution to this problem?
I managed to find the solution. The problem was the datatrigger binding instead of Data.SaveStatus should be RowData.Row.SaveStatus:
<Style.Triggers>
<DataTrigger Binding="{Binding Path=RowData.Row.SaveStatus, UpdateSourceTrigger=PropertyChanged}" Value="{x:Static enums:SaveState.DoneSuccesfuly}">
<Setter Property="Source" Value="..\Icons\StatusOk.png"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=RowData.Row.SaveStatus, UpdateSourceTrigger=PropertyChanged}" Value="{x:Static enums:SaveState.DoneUnsuccesfuly}">
<Setter Property="Source" Value="..\Icons\StatusError.png"></Setter>
</DataTrigger>
</Style.Triggers>
Try accessing you images like this:
<Style TargetType="{x:Type Image}" x:Key="ImageStatusStyle">
<Style.Triggers>
<Setter Property="Source" Value="/ApplicationName;component/Icons/StatusOk.png" />
<DataTrigger Binding="{Binding Path=Data.SaveStatus, UpdateSourceTrigger=
PropertyChanged}" Value="{x:Static enums:SaveState.DoneUnsuccesfuly}">
<Setter Property="Source" Value="/ApplicationName;component/Icons/StatusError.png" />
</DataTrigger>
</Style.Triggers>
</Style>

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

WPF DataTrigger Works for Image but not for Path

The following dims the image when I disable the button and show clearly when enabled:
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type UIElement}, AncestorLevel=1}, Path=IsEnabled}" Value="False">
<Setter Property="Opacity" Value="0.25"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
...
<Button Name="btnPageFirst" IsEnabled="False">
<Image Source="..\Resources\imgMoveFirst.png" />
</Button>
I want to do a similar effect but with Path. I want to gray the image. But it does not gray and there is no error.
<Style TargetType="{x:Type Path}">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type UIElement}, AncestorLevel=1}, Path=IsEnabled}" Value="False">
<Setter Property="Fill" Value="Gray"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
...
<Button Name="btnPageFirst" IsEnabled="False">
<Path Data="F1M820.557,535.025L838.189,535.024 817.857,555.36 857.82,555.36 857.82,568.301 817.998,568.301 838.226,588.531 820.557,588.499 793.82,561.765 820.557,535.025z" Stretch="Uniform" Fill="DodgerBlue" Width="16" Height="16" Margin="0,0,0,0" />
</Button>
There is a precedence order which is used to calculate the values of the dependency properties during runtime.
The oversimplified precedence list:
Local value (what you set on the control)
Triggers
Style setters
Your problem is that you set Fill="DodgerBlue" on your path and because it has higher precedence then the Trigger that is way you don't see the fill change. Also that is why it works for your Image because there you don't set the Opacity directly.
To make it work:
Remove the Fill="DodgerBlue" from your path
Set it in your style:
<Style TargetType="{x:Type Path}">
<Style.Setters>
<Setter Property="Fill" Value="DodgerBlue"/>
</Style.Setters>
<Style.Triggers>
<!-- ... -->
</Style.Triggers>
</Style>
As a side note: if you always "inside" in a button you can rewrite the RelativeSource to:
RelativeSource={RelativeSource AncestorType={x:Type Button}}

UserControl property trigger for child control

Depending on the IsEnabled property of my UserControl (true/false), I want the controls inside it have different colors. I want to do so with the 'magic' of XAML.
<UserControl.Resources>
<Style x:Key="EnableDependent" TargetType="{x:Type Shape}">
<Style.Triggers>
<Trigger Property="{Binding Path=IsEnabled, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="True">
<Setter Property="Stroke" Value="White" />
</Trigger>
<Trigger Property="{Binding Path=IsEnabled, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="False">
<Setter Property="Stroke" Value="Black" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
The style is applied in a ViewBox where a Path is drawn:
<Viewbox Grid.Column="3" Width="18" Margin="5,5,2,5" MouseEnter="Dispatch_MouseEnter" DockPanel.Dock="Right" Stretch="Uniform">
<Path Data="M0,1 L4,1 M2,0 L4,1 L2,2" Stretch="Fill" StrokeThickness="3" Width="12" Height="12" Style="{StaticResource EnableDependent}" />
</Viewbox>
I get a runtime exception that a binding cannot be set in the 'Property' property of a trigger.
So what is the way to do this?
Use a DataTrigger instead of a normal Trigger which is for internal property changes, it has a Binding-Property where you can do that.
<Style x:Key="EnableDependent" TargetType="{x:Type Shape}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="True">
<Setter Property="Stroke" Value="White" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=IsEnabled, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" Value="False">
<Setter Property="Stroke" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>

Resources