How to properly execute a command upon animation i

2019-09-19 01:56发布

问题:

I have a button as follows:

<Button x:Name ="Btn_Import" Grid.Row="33" Grid.Column="15" Grid.ColumnSpan="36" Grid.RowSpan="36" >
            <Button.Template>
                <ControlTemplate>
                    <Grid RenderTransformOrigin="0.5,0.5" x:Name="bg">
                        <Image x:Name ="import_image" Source="{Binding ImportBtnBaseImagePath}"/>

                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="import_image" Property="Source" Value="{Binding ImportBtnOverImagePath}" />
                        </Trigger>

                        <Trigger Property="ButtonBase.IsPressed"  Value ="True">
                            <!-- press effect -->
                            <Setter TargetName="bg" Property="RenderTransform">
                                <Setter.Value>
                                    <ScaleTransform ScaleX="0.9" ScaleY="0.9"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Button.Template>

            <Button.Triggers>
                <EventTrigger RoutedEvent="PreviewMouseDown" >
                    <BeginStoryboard>
                        <Storyboard>
                            <DoubleAnimation Storyboard.TargetName="Studio" Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:2" >
                                <i:Interaction.Triggers>
                                    <i:EventTrigger EventName="Completed">
                                        <i:InvokeCommandAction Command="{Binding NavigateCommand}" CommandParameter="ImportButtonClickParmeters" />
                                    </i:EventTrigger>
                                </i:Interaction.Triggers>
                            </DoubleAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </Button.Triggers>

        </Button>

I want this button to triger an animation on some other control to fade out for 2 seconds, and then once the animation is completed to navigate to some other view through 'NavigateCommand'. But I get the following error:

Additional information: Specified value of type 'System.Windows.Interactivity.EventTrigger' must have IsFrozen set to false to modify.

回答1:

Your issue depends on a well know bug. Unluckly I found that the common solution does not properly work in this case.

Anyway if you wish to keep your application MVVM compliant, I suggest you to create a "fake" animation, whose task is to execute a command. Of course this animation has to be the last one in your storyboard.

This is the CommandFakeAnimation code:

public class CommandFakeAnimation : AnimationTimeline
{
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("Command", typeof(ICommand), typeof(CommandFakeAnimation), new UIPropertyMetadata(null));

    public static readonly DependencyProperty CommandParameterProperty =
        DependencyProperty.Register("CommandParameter", typeof(object), typeof(CommandFakeAnimation), new PropertyMetadata(null));

    public CommandFakeAnimation()
    {
        Completed += new EventHandler(CommandAnimation_Completed);
    }

    public ICommand Command
    {
        get
        {
            return (ICommand)GetValue(CommandProperty);
        }
        set
        {
            SetValue(CommandProperty, value);
        }
    }

    public object CommandParameter
    {
        get 
        {
            return GetValue(CommandParameterProperty);
        }
        set
        {
            SetValue(CommandParameterProperty, value);
        }
    }

    private void CommandAnimation_Completed(object sender, EventArgs e)
    {
        if (Command != null && Command.CanExecute(CommandParameter))
        {
            Command.Execute(CommandParameter);
        }
    }

    protected override Freezable CreateInstanceCore()
    {
        return new CommandFakeAnimation();
    }

    public override Type TargetPropertyType
    {
        get
        {
            return typeof(Object);
        }
    }

    public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock)
    {
        return defaultOriginValue;
    }
}

As you can see you can apply this animation to whatever dependecy property that you wish, since it does not change its value. It just execute a command when it is completed.

Now we can use the new animation in the XAML:

<Button.Triggers>
    <EventTrigger RoutedEvent="PreviewMouseDown">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:2" />
                <local:CommandFakeAnimation Duration="0:0:0" Command="{Binding Path=YourCommand, Mode=OneWay}"
                                            CommandParameter="{Binding Path=YourParameter, Mode=OneWay}" 
                                            Storyboard.TargetProperty="Opacity" />
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Button.Triggers>

I hope it can help you.



标签: wpf mvvm