119

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?

Pavel Anikhouski
  • 21,776
  • 12
  • 51
  • 66
nabulke
  • 11,025
  • 13
  • 65
  • 114

3 Answers3

289

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}

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154
  • 1
    I added the `xmlns` like this: `xmlns:local="clr-namespace:MyCompany.Testbench"` and the trigger like that ``. No I get the error `Cannot find the type 'PingStatus'`. – nabulke Dec 18 '12 at 08:01
  • 1
    `enum PingStatus` is defined inside the class `MyCompany.TestBench.ConfigurationViewModel`. Do I have to add the class name somewhere? – nabulke Dec 18 '12 at 08:03
  • It works with your solution _if_ I move the `enum PingStatus` out of class scope. Why? – nabulke Dec 18 '12 at 08:29
  • 3
    Thank you. I couldn't find the syntax for a nested type anywhere. Where is the "+" syntax documented? I can't find it in MSDN or in the WPF books I have. I thought it should be in [x:Static Markup Extension](http://msdn.microsoft.com/en-us/library/ms742135.aspx) but it's not. – skst May 29 '13 at 21:58
  • 1
    @skst The + symbol differentiates the containing type from a nested namespace. `Type t = typeof (System.Environment.SpecialFolder); Console.WriteLine (t.FullName); // prints System.Environment+SpecialFolder` –  Jun 28 '16 at 19:08
  • 2
    @skst http://stackoverflow.com/questions/2443244/c-sharp-having-a-in-the-class-name –  Jun 28 '16 at 19:15
  • I think this answer needs to be updated. This solution did not work for me anymore but just using the enum value as string works. Have they changed it at some point? I'm using Xamarin.Forms version 3.3.0.912540 – hamalaiv Nov 27 '18 at 09:27
  • @hamalaiv AFAIK, xaml in wpf is different than xaml in Xamarin.Forms. – Xam Feb 09 '19 at 00:22
  • why this breaks designer? – Piotr Golacki Oct 26 '22 at 13:21
5

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.

Contango
  • 76,540
  • 58
  • 260
  • 305
3

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>
Adam Silenko
  • 3,025
  • 1
  • 14
  • 30