datatrigger on enum to change image
I've got a button with a fixed background image and would like to show a small overlay image on top of it. Which overlay image to chose depends on a dependency property (LapCounterPingStatus
) of the according viewmodel.
This is what I got so far:
<Button>
<Grid>
<Image Stretch="None"> <!-- Background Image -->
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="/Images/Pingn.png"/>
</Style>
</Image.Style>
</Image>
<Image Stretch="None" Panel.ZIndex="1"> <!-- Small Overlay Image -->
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="PingStatus.PING_UNKNOWN">
<Setter Property="Source" Value="/Images/RefreshOverlayn.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="PingStatus.PING_FAILURE">
<Setter Property="Source" Value="/Images/ErrorOverlayn.png"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="PingStatus.PING_SUCCESS">
<Setter Property="Source" Value="/Images/CheckmarkOverlayn.png"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</Grid>
</Button>
Relevant parts of my viewmodel
public class ConfigurationViewModel
{
public enum PingStatus { PING_UNKNOWN, PING_SUCCESS, PING_FAILURE };
public PingStatus LapCounterPingStatus
{
get { return _lapCounterPingStatus; }
set
{
_lapCounterPingStatus = value;
RaisePropertyChanged(LapCounterPingStatusPropertyName);
}
}
}
Right now, no overlay image at all is displayed. What could be wrong?
UPDATE
Trace window of my IDE is showing System.ArgumentException
and System.FormatException
.
Could the problem source be a unknown type of enumeration PingStatus
im the XAML?
You need 2 things to get this working:
1 - Add an xmlns
reference in the root element of your XAML file, to the namespace where your Enum is defined:
<UserControl ...
xmlns:my="clr-namespace:YourEnumNamespace;assembly=YourAssembly">
2 - in the Value
property of the DataTrigger
, use the {x:Static}
form:
<DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="{x:Static my:PingStatus.PING_UNKNOWN}">
Notice that the Enum type must be prefixed with the xmlns prefix you defined above.
Edit:
If your Enum is declared inside a class you need to use the syntax:
{x:Static namespace:ClassName+EnumName.EnumValue}
for example:
{x:Static my:ConfigurationViewModel+PingStatus.PING_UNKNOWN}
Complete worked example for WPF + MVVM.
Tested on MSVC 2017.
In the view:
<TextBlock Text="Some text to be colored by an enum">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding StatusIcon}" Value="{x:Static my:StatusIcon.Warning}">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
<DataTrigger Binding="{Binding StatusIcon}" Value="{x:Static my:StatusIcon.Error}">
<Setter Property="Foreground" Value="Red}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
If using ReSharper, and if the DataContext is set up properly, there will be intellisense when you hit the .
after StatusIcon
, i.e. it will show the properties of the enum which are Debug
, Info
, Warning
or Error
.
If using ReSharper, it will suggest the following update to the namespace in the header for the XAML file(its good like that):
xmlns:my="clr-namespace:Class.Path.MyViewModel;assembly=MyAssembly"
And the VieModel:
public enum StatusIcon
{
Debug,
Info,
Warning,
Error
}
public class MyViewModel
{
public StatusIcon StatusIcon { get; }
}
We also use Fody
for automated binding.
You can simply set enum value as DataTrigger Value... Tested on MSVC 2017.
<TextBlock Text="Some text to be colored by an enum">
<TextBlock.Style>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding StatusIcon}" Value="Warning">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
<DataTrigger Binding="{Binding StatusIcon}" Value="Error">
<Setter Property="Foreground" Value="Red}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>