3
votes

I have a small ellipse that I want to flash every time a dependency property gets set to true. Because the property can very quickly go from true back to false in a matter of milliseconds, I need to do this with an animation and not a simple style datatrigger. Basically, I just want the true value to ping an animation on the ellipse.

<Ellipse Height="10" Width="10" Stroke="#FFFFFFFF" Margin="5,3,0,0">
    <Ellipse.Fill>
        <SolidColorBrush />
    </Ellipse.Fill>
    <Ellipse.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsReceiving}" Value="True" >
                    <DataTrigger.EnterActions>
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Fill.Color">
                                    <ColorAnimationUsingKeyFrames.KeyFrames>
                                        <DiscreteColorKeyFrame KeyTime="0:0:0" Value="Red"/>
                                        <DiscreteColorKeyFrame KeyTime="0:0:0.25" Value="Transparent"/>
                                    </ColorAnimationUsingKeyFrames.KeyFrames>
                                </ColorAnimationUsingKeyFrames>
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Ellipse.Style>
</Ellipse>

This animation seems to work, but it only fires the first time the value reaches true. Am I missing something?

UPDATE: Thanks for the input everybody. It turns out, it was a threading issue. Originally, I had a DP on the control that was bound to a view model that implemented INotifyPropertyChanged. I then tried removing the DP on the control and turning my view model property into a DP. Boom, that's when I started getting an error stating that a different thread owned the object. I realized I needed to incorporate some Observables using Reactive Extensions as I had done in other parts of the app. I reverted back to the view model traditional property with PropertyChanged() and simply bound that to the control's animation. Everything is working flawlessly now.

6

6 Answers

7
votes

I had a similar problem where I had an 'in' and 'out' animation to be fired when a DP changed. The first cycle worked fine but after that nothing happened. I solved it by adding RemoveStoryboard EnterActions before the BeginStoryboard actions.

<Border Name="Zyzzyx" Grid.Row="1" Background="DarkRed" Height="0" VerticalAlignment="Bottom">
    <Border.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=SelectionState, ElementName=ControlRoot, Mode=OneWay}" Value="Selecting">
                    <DataTrigger.EnterActions>
                        <RemoveStoryboard BeginStoryboardName="AnimateIn" />
                        <RemoveStoryboard BeginStoryboardName="AnimateOut" />
                        <BeginStoryboard Name="AnimateIn" HandoffBehavior="SnapshotAndReplace">
                            <Storyboard FillBehavior="HoldEnd" Duration="0:0:5">
                                <DoubleAnimation To="30" Duration="0:0:5" Storyboard.TargetProperty="Height" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=SelectionState, ElementName=ControlRoot, Mode=OneWay}" Value="Deselecting">
                    <DataTrigger.EnterActions>
                        <RemoveStoryboard BeginStoryboardName="AnimateIn" />
                        <RemoveStoryboard BeginStoryboardName="AnimateOut" />
                        <BeginStoryboard Name="AnimateOut" HandoffBehavior="SnapshotAndReplace">
                            <Storyboard FillBehavior="HoldEnd" Duration="0:0:5">
                                <DoubleAnimation To="0" Duration="0:0:5" Storyboard.TargetProperty="Height" />
                            </Storyboard>
                        </BeginStoryboard>
                    </DataTrigger.EnterActions>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Border.Style>

<!-- Border content -->

</Border>
2
votes
                <DataTrigger.EnterActions>
                    <RemoveStoryboard BeginStoryboardName="AnimateIn" />
                    <RemoveStoryboard BeginStoryboardName="AnimateOut" />
                    <BeginStoryboard ...>
                </DataTrigger.EnterActions>

works but i think it is better to use

                <DataTrigger.EnterActions>
                    <BeginStoryboard Name="FadeIn"...>
                </DataTrigger.EnterActions>
                <DataTrigger.ExitActions>
                    <RemoveStoryboard BeginStoryboardName="FadeIn" />
                </DataTrigger.ExitActions>
1
votes
 <Ellipse Height="10" Width="10" Stroke="#FFFFFFFF" Margin="5,3,0,0">
        <Ellipse.Fill>
            <SolidColorBrush />
        </Ellipse.Fill>
        <Ellipse.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding IsReceiving,Mode=TwoWay}" Value="True" >
                        <DataTrigger.EnterActions>
                            <BeginStoryboard>
                                <Storyboard>
                                    <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="Fill.Color">
                                        <ColorAnimationUsingKeyFrames.KeyFrames>
                                            <DiscreteColorKeyFrame KeyTime="0:0:0" Value="Red"/>
                                            <DiscreteColorKeyFrame KeyTime="0:0:0.25" Value="Transparent"/>
                                        </ColorAnimationUsingKeyFrames.KeyFrames>
                                    </ColorAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </DataTrigger.EnterActions>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Ellipse.Style>
    </Ellipse>

Try to use Mode=TwoWay

1
votes

I also saw a similar issue to fix my issue I found I had to add a StopStoryboard tag in the ExitActions of the DataTrigger.

0
votes

You'll need to supply the definition for the IsReceiving property to be sure. Based on the assumption that you've got a property (IsReceiving) that toggles between True and False which will trigger this animation effect: If you're only seeing the effect triggered once then:

1) Check that the property is either a DependencyProperty or utilizing INotifyPropertyChanged correctly to signal updates to the View.
2) Check that the property setter is actually changing from True to False and back.

0
votes

I can't reproduce your problem. Here's my codebehind :

public partial class MainWindow : Window
{
    public static readonly DependencyProperty IsReceivingProperty =
        DependencyProperty.Register("IsReceiving",
                                    typeof(bool), typeof(MainWindow));

    public bool IsReceiving
    {
        get { return (bool)GetValue(IsReceivingProperty); }
        set { SetValue(IsReceivingProperty, value); }
    }

    public MainWindow()
    {
        InitializeComponent();

        myEllipse.DataContext = this;
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        this.IsReceiving = true;
        this.IsReceiving = false;
    }
}