Search code examples
wpfxamlanimationpropertiesstoryboard

Trying to begin a storyboard on change of a property in WPF application


I have a simple MVVM application. It contains a property, which I will change to true when a method correctly executes, and false if it does not. When this property changes, for a few seconds I would like to display "Passed" or "Failed" on the status bar of my WPF application and then have it fade away.

So I have read StackOverflow, and Googled intensely, to no avail. I think I have misunderstood how I need to structure the Storyboard.

In my StatusBar I have added a storyboard, which I am trying to trigger in <UserControl.Resources> at the beginning of my XAML file. Is this correct ? At the moment I am using dummy values of 0/1, I assume the correct practice would be to use a BooleanToString converter I could make, or perhaps there is a better way?

So my status bar contains :

<StatusBar >
  <StatusBar.Resources>
    <Storyboard x:Key="StatusBar" >
      <DoubleAnimationUsingKeyFrames 
                    Storyboard.TargetProperty="(UIElement.Opacity)" 
                    Storyboard.TargetName="statusBarItem">
        <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
        <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
        <EasingDoubleKeyFrame KeyTime="0:0:3" Value="1"/>
        <EasingDoubleKeyFrame KeyTime="0:0:4" Value="0"/>
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>
  </StatusBar.Resources>
</StatusBar>  

and I am trying to register for this to be called in my UserControl.Resources :

<UserControl.Resources> <DataTemplate.Triggers> </DataTemplate.Triggers> </UserControl.Resources>

Do I have my structure completely backwards ? It will not compile and I get the error :

A value of type 'BeginStoryboard' cannot be added to a collection or dictionary of type 'SetterBaseCollection'. 

Any help, resources or information would be very much appreciated. Thanks a lot.


Solution

  • Here's an example. You need to use a trigger to start the storyboard.

    <Grid>
        <Grid.DataContext>
            <WpfApplication1:MainViewModel/>
        </Grid.DataContext>
    
        <Grid.Resources>
            <Style x:Key="statusStyle" TargetType="StatusBar">
                <Setter Property="Opacity" Value="0"/>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Pulse}" Value="True">
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <DoubleAnimationUsingKeyFrames 
                                        AutoReverse="True" 
                                        Storyboard.TargetProperty="(UIElement.Opacity)" >
                                        <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                                        <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1"/>
                                        <EasingDoubleKeyFrame KeyTime="0:0:3" Value="1"/>
                                        <EasingDoubleKeyFrame KeyTime="0:0:4" Value="0"/>
                                    </DoubleAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
    
        <StatusBar Style="{StaticResource statusStyle}" 
                           Grid.Row="1" ItemsSource="{Binding Items}" />
        <CheckBox Content="CheckBox" Height="16" 
                          HorizontalAlignment="Left" Margin="41,30,0,0" 
                          IsChecked="{Binding Pulse}" VerticalAlignment="Top" />
    </Grid>
    

    View model

    public class MainViewModel : ViewModelBase
    {
        private bool _pulse;
    
        public MainViewModel()
        {
            Items = new[] {"Passed"};
        }
    
        public IList<string> Items { get; private set; }
    
        public bool Pulse
        {
            get { return _pulse; }
            set { Set(()=>Pulse, ref _pulse, value); }
        }
    }