datatrigger on enum, aby zmienić obraz

101

Mam przycisk ze stałym obrazem tła i chciałbym pokazać na nim mały obraz nakładki. Wybór obrazu nakładki zależy od właściwości zależności ( LapCounterPingStatus) odpowiedniego modelu widoku.

Oto, co osiągnąłem do tej pory:

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

Odpowiednie części mojego modelu widoku

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

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

W tej chwili w ogóle nie jest wyświetlany obraz nakładki. Co się stało?


AKTUALIZACJA

Wyświetla się okno śledzenia mojego IDE System.ArgumentExceptioni System.FormatException. Czy źródłem problemu może być nieznany typ wyliczenia PingStatusw języku XAML?

nabulke
źródło
Powiązane: stackoverflow.com/q/10250925/590790 Chociaż ten facet już to działa.
Steven Jeuris

Odpowiedzi:

249

Aby to działało, potrzebujesz 2 rzeczy:

1 - Dodaj xmlnsodwołanie w elemencie głównym pliku XAML, do przestrzeni nazw, w której zdefiniowano Enum:

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

2 - na Valuewłasność DataTriggernależy skorzystać z {x:Static}formularza:

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

Zwróć uwagę, że typ Enum musi być poprzedzony prefiksem xmlns zdefiniowanym powyżej.

Edytować:

Jeśli Twój Enum jest zadeklarowany wewnątrz klasy, musisz użyć składni:

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

na przykład:

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

Federico Berasategui
źródło
1
Dodałem xmlnstak: xmlns:local="clr-namespace:MyCompany.Testbench"i taki spust <DataTrigger Binding="{Binding Path=LapCounterPingStatus}" Value="{x:Static local:PingStatus.PING_UNKNOWN}">. Nie, pojawia się błąd Cannot find the type 'PingStatus'.
nabulke
1
enum PingStatusjest zdefiniowana w klasie MyCompany.TestBench.ConfigurationViewModel. Czy muszę gdzieś dodać nazwę klasy?
nabulke
3
Dziękuję Ci. Nigdzie nie mogłem znaleźć składni dla typu zagnieżdżonego. Gdzie jest udokumentowana składnia „+”? Nie mogę go znaleźć w MSDN ani w książkach WPF, które posiadam. Pomyślałem, że powinno być w rozszerzeniu x: Static Markup, ale tak nie jest.
skst
1
@skst Symbol + odróżnia typ zawierający od zagnieżdżonej przestrzeni nazw. Type t = typeof (System.Environment.SpecialFolder); Console.WriteLine (t.FullName); // prints System.Environment+SpecialFolder
3

Kompletny działający przykład dla WPF + MVVM.

Testowane na MSVC 2017.

W widoku:

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

W przypadku korzystania z ReSharper, a jeżeli DataContext jest ustawiony prawidłowo, nie będzie intellisense gdy trafisz .po StatusIcon, czyli pokaże właściwości wyliczenia, które są Debug, Info, Warninglub Error.

Jeśli używasz ReSharper, zasugeruje następującą aktualizację przestrzeni nazw w nagłówku pliku XAML (tak dobrze):

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

Oraz VieModel:

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

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

Używamy również Fodydo automatycznego wiązania.

Contango
źródło
Czy masz na myśli projekt PropertyChanged firmy Fody?
UuDdLrLrSs