Search code examples
c#xamlanimationwindows-phone-8popup

Windows Phone - popup animation on tap


I'm working on a popup with slide-in and slide-out effects.
I figured out the "in" part. I added an EventTrigger to begin a storyboard when the control's grid loads up.

<Grid.Triggers>
    <EventTrigger RoutedEvent="Grid.Loaded">
        <BeginStoryboard>
            <Storyboard>
                <DoubleAnimation Storyboard.TargetName="SlideTransform"
                                 Storyboard.TargetProperty="Y"
                                 From="1000" To="0" Duration="0:0:0.25"/>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Grid.Triggers>

<Grid.RenderTransform>
    <TranslateTransform x:Name="SlideTransform" Y="1000"/>
</Grid.RenderTransform>

I also bind a ViewModel command to the tap event to close the popup:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Tap">
        <cmd:EventToCommand Command="{Binding DismissCommand}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

This command is also used on a button placed below this grid (in the "LayoutRoot" master grid).
All of that works fine.

Now here's the problem - I need to add a "slide-out" animation BEFORE the popup gets closed. I can't add

<EventTrigger RoutedEvent="Grid.Tap">

Because I get a xaml parse exception at startup:

Additional information: Failed to assign to property 'System.Windows.EventTrigger.RoutedEvent'.

I tried adding a "Tap" event handler to the whole control, but it seems like the ViewModel command gets triggered first and closes the whole popup.
Any ideas on how I could put it all together?


Solution

  • So I figured it out as well, in case someone's interested.
    On each button's Tap event I call a method, that prepares and triggers the animation:

    private void DismissButton_Tap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        this.dismissAll = false;
        this.PrepareAndStartSlideOutAnimation();
    }
    
    private void DismissAllButton_Tap(object sender, System.Windows.Input.GestureEventArgs e)
    {
        this.dismissAll = true;
        this.PrepareAndStartSlideOutAnimation();
    }
    
    private void PrepareAndStartSlideOutAnimation()
    {
        Storyboard s = new Storyboard();
        DoubleAnimation animation = new DoubleAnimation();
        animation.From = 0;
        animation.To = 1000;
        animation.Duration = new Duration(TimeSpan.FromMilliseconds(250));
    
        LayoutRoot.RenderTransform = new CompositeTransform();
    
        Storyboard.SetTarget(animation, LayoutRoot);
        Storyboard.SetTargetProperty(animation, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateY)"));
    
        s.Completed += SlideOutAnimation_Completed;
        s.Children.Add(animation);
        s.Begin();
    }
    

    and when the animation completes, I execute a command from the DataContext:

    private void SlideOutAnimation_Completed(object sender, EventArgs e)
    {
        if (!this.dismissAll)
            (this.DataContext as HelpOverlayControlViewModel).DismissCommand.Execute(null);
        else
            (this.DataContext as HelpOverlayControlViewModel).DismissAllCommand.Execute(null);
    }
    

    It's not the most "MVVMy" of solutions, but I guess popup animations aren't really the ViewModel's concern, so I'll leave it as it is.