datatrigger on enum pour changer l'image

100

J'ai un bouton avec une image d'arrière-plan fixe et j'aimerais afficher une petite image de superposition par-dessus. L'image de superposition à choisir dépend d'une propriété de dépendance ( LapCounterPingStatus) du modèle de vue correspondant.

Voici ce que j'ai obtenu jusqu'à présent:

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

Parties pertinentes de mon modèle de vue

public class ConfigurationViewModel
{
    public enum PingStatus { PING_UNKNOWN, PING_SUCCESS, PING_FAILURE };

    public PingStatus LapCounterPingStatus
    {
        get { return _lapCounterPingStatus; }
        set
        {
            _lapCounterPingStatus = value;
            RaisePropertyChanged(LapCounterPingStatusPropertyName);
        }
    }
}

À l'heure actuelle, aucune image de superposition n'est affichée. Qu'est-ce qui ne va pas?


METTRE À JOUR

La fenêtre de trace de mon IDE s'affiche System.ArgumentExceptionet System.FormatException. La source du problème pourrait-elle être un type d'énumération inconnu dans PingStatusle XAML?

nabulke
la source
En relation: stackoverflow.com/q/10250925/590790 Bien que ce type l'ait déjà fait fonctionner.
Steven Jeuris

Réponses:

247

Vous avez besoin de 2 choses pour que cela fonctionne:

1 - Ajoutez une xmlnsréférence dans l'élément racine de votre fichier XAML, à l'espace de noms où votre Enum est défini:

<UserControl ...
xmlns:my="clr-namespace:YourEnumNamespace;assembly=YourAssembly"> 

2 - dans la Valuepropriété du DataTrigger, utilisez le {x:Static}formulaire:

 <DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="{x:Static my:PingStatus.PING_UNKNOWN}">

Notez que le type Enum doit être précédé du préfixe xmlns que vous avez défini ci-dessus.

Éditer:

Si votre Enum est déclaré dans une classe, vous devez utiliser la syntaxe:

{x:Static namespace:ClassName+EnumName.EnumValue}

par exemple:

{x:Static my:ConfigurationViewModel+PingStatus.PING_UNKNOWN}

Federico Berasategui
la source
1
J'ai ajouté le xmlnscomme ceci: xmlns:local="clr-namespace:MyCompany.Testbench"et le déclencheur comme ça <DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="{x:Static local:PingStatus.PING_UNKNOWN}">. Non, j'obtiens l'erreur Cannot find the type 'PingStatus'.
nabulke
1
enum PingStatusest défini à l'intérieur de la classe MyCompany.TestBench.ConfigurationViewModel. Dois-je ajouter le nom de la classe quelque part?
nabulke
3
Je vous remercie. Je n'ai trouvé nulle part la syntaxe d'un type imbriqué. Où la syntaxe "+" est-elle documentée? Je ne peux pas le trouver dans MSDN ou dans les livres WPF que j'ai. Je pensais que cela devrait être dans x: Static Markup Extension mais ce n'est pas le cas.
skst
1
@skst Le symbole + différencie le type conteneur d'un espace de noms imbriqué. Type t = typeof (System.Environment.SpecialFolder); Console.WriteLine (t.FullName); // prints System.Environment+SpecialFolder
2

Exemple de travail complet pour WPF + MVVM.

Testé sur MSVC 2017.

Dans la vue:

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

Si vous utilisez ReSharper, et si le DataContext est correctement configuré, il y aura IntelliSense quand vous frappez la .suite StatusIcon, ce qu'il affiche les propriétés de l'ENUM qui sont Debug, Info, Warningou Error.

Si vous utilisez ReSharper, il suggérera la mise à jour suivante de l'espace de noms dans l'en-tête du fichier XAML (c'est bien comme ça):

xmlns:my="clr-namespace:Class.Path.MyViewModel;assembly=MyAssembly"

Et le VieModel:

public enum StatusIcon
{
    Debug,
    Info,
    Warning,
    Error
}

public class MyViewModel
{
    public StatusIcon StatusIcon { get; }
}

Nous utilisons également Fodypour la liaison automatique.

Contango
la source
Faites-vous référence au projet PropertyChanged de Fody?
UuDdLrLrSs