Niksen
Niksen

Reputation: 79

WPF MVVM - Trigger storyboard on property change only happens once

In my view model, I have a timer that needs to make a border background blink every 5 minutes.

The border in my view:

<Border Name="btnBorder" Grid.Row="0" Grid.Column="0" Opacity="1" CornerRadius="10,10,0,0">
    <Border.Style>
        <Style TargetType="Border">
            <Style.Setters>
                <Setter Property="Background" Value="#e2e2e2"></Setter>
            </Style.Setters>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=ViewEventTrigger}" Value="True">
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
                                    <EasingColorKeyFrame KeyTime="00:00:00.000" Value="#e2e2e2"/>
                                    <EasingColorKeyFrame KeyTime="00:00:00.500" Value="#163f6b"/>
                                    <EasingColorKeyFrame KeyTime="00:00:01.000" Value="#e2e2e2"/>
                                    <EasingColorKeyFrame KeyTime="00:00:01.500" Value="#163f6b"/>
                                    <EasingColorKeyFrame KeyTime="00:00:02.000" Value="#e2e2e2"/>
                                    <EasingColorKeyFrame KeyTime="00:00:02.500" Value="#163f6b"/>
                                    <EasingColorKeyFrame KeyTime="00:00:03.000" Value="#e2e2e2"/>
                                    <EasingColorKeyFrame KeyTime="00:00:03.500" Value="#163f6b"/>
                                    <EasingColorKeyFrame KeyTime="00:00:04.000" Value="#e2e2e2"/>
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Border.Style>
</Border>

Property from view model:

private string _viewEventTrigger = "";
public string ViewEventTrigger
{
    get => _viewEventTrigger ?? (_viewEventTrigger = "");
    private set
    {
        if (_viewEventTrigger == value)
            return;

        _viewEventTrigger = value;
        OnPropertyChanged();
    }
}

And the method that needs to trigger the... well, trigger:

private void ShowInfocenterIfAnyItinirary(object sender, ElapsedEventArgs e)
{
    ViewEventTrigger = "";
    ViewEventTrigger = "True";
}

I testet the Storyboard by triggering it with MouseEnter. But I am not able to make it work by binding it to my property.

EDIT:

I set the datacontext like this:

d:DataContext="{d:DesignInstance local:ItineraryViewModel}"

Also, I have lots og other databindings that work fine, like data to show and commands for buttons. But I just can't make the trigger execute the storybord.

The method ShowInfocenterIfAnyItinirary() is executed by a timer, started in the viewmodel.

Timer code:

private readonly Timer _timer = new Timer();
public ItineraryViewModel()
{
    _timer.Interval = 5000;
    _timer.Elapsed += ShowInfocenterIfAnyItinirary;
    _timer.Start();
}

EDIT 2:

I have delayed when the animation should start when the program runs. I have discovered that the animation DOES run, but only once. I did not see it before, because the window starts minimized.

Why does it only run once, no matter how many times the trigger event happens?

Upvotes: 1

Views: 666

Answers (2)

Niksen
Niksen

Reputation: 79

I ended up solving the problem like this:

private void ShowInfocenterIfAnyItinirary(object sender, ElapsedEventArgs e)
{
    if (Items.Count <= 0) return;
    GlobalEvents.TriggerShowMainWindowEvent();
    ViewEventTrigger = "True";
    Task.Run(async () =>
    {
        Thread.Sleep(4000);
        ViewEventTrigger = "False";
    });
}

This stops the animation, instead of leaving it paused at the end point.

Upvotes: 0

mm8
mm8

Reputation: 169200

This only sets the design time data context:

d:DataContext="{d:DesignInstance local:ItineraryViewModel}"

This won't have any effect when you actualy run the application.

You should set the DataContext property of the view to an instance of your view model:

<Window ...>
    <Window.DataContext>
        <local:ItineraryViewModel />
    </Window.DataContext>

Upvotes: 1

Related Questions