Does anyone know if it is possible to trigger an animation when a WPF ContextMenu closes?
I have code that triggers an animation when the ContextMenu is opened. The animation makes the context menu fade into view. I also want an animation when the ContextMenu is closed that makes it fade out.
The code that starts the opened fade-in animation looks something like this:
var animation = new DoubleAnimation();
animation.From = 0;
animation.To = 1;
animation.Duration = TimeSpan.FromSeconds(0.2);
animation.Freeze();
menu.BeginAnimation(ContextMenu.OpacityProperty, animation);
The fade-in animation also runs on sub-menu items.
Note that I also want to run other animations besides fade in and fade out. Eg I want the context menu to scale up from nothing so that it sort of 'bounces' into view.
Other than Popup.PopupAnimation, there is no hook within ContextMenu or Popup to allow you to delay the dismantling of the ContextMenu, destruction of the window, etc, long enough to show your animation. This leaves you with several choices:
Using Popup.PopupAnimation
In the ContextMenuOpened event, find the popup and set Popup.PopupAnimation to any animation, then monitor Popup.IsOpen and when the IsOpen property goes false, use a Dispatcher callback to replace the scheduled animation with your own. Your animation can reuse the TranslateTransform created by the Popup class or it can add its own transform.
This techinique is simple and compatible, but the drawback is that you have no control over the duration of the (fixed) interval between the time the popup decides to close and the time everything is dismantled. It seems to be about 1/6 second, so if you can live with that this is probably the way to go.
Using your own Popup to display the ContextMenu during the close animation
By the time you get ContextMenuClosing the Popup that was displaying the menu is already gone, but you can temporarily create a new one.
To avoid flicker, this must be done at DisplatchPriority.Render or higher. Also, the new Popup must be at exactly the same position and size as the one created during menu popup. These coordinates can be recorded immediately after the ContextMenuOpened event. You'll have to do this in a Dispatcher callback because the coordinates aren't actually available during the ContextMenuOpened event.
So the procedure is as follows:
Implementing your own ContextMenu handling code
If you mark your ContextMenuEventArgs.Handled true in the ContextMenuOpened event, the ContextMenu code doesn't actually do anything, allowing you to present the ContextMenu yourself. To do this:
The tricky part of this is reliably deciding when to close the ContextMenu (step 3) based on user actions. I don't know of any way to reuse NET Framework's built-in mechanisms for this and the rules for when the ContextMenu should close are quite complex.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With