[ACCEPTED]-Fading out a wpf window on close-routedevent
Closing is not a routed event, so you can't 4 use it in an EventTrigger. Perhaps you could 3 start the storyboard in the handler of the 2 ClosingEvent in the code-behind and cancel 1 the event... something like that :
private bool closeStoryBoardCompleted = false;
private void Window_Closing(object sender, CancelEventArgs e)
{
if (!closeStoryBoardCompleted)
{
closeStoryBoard.Begin();
e.Cancel = true;
}
}
private void closeStoryBoard_Completed(object sender, EventArgs e)
{
closeStoryBoardCompleted = true;
this.Close();
}
I thought I'd add another solution of doing 18 this, using behaviors from the Expression 17 SDK and combining it with the solution from 16 @Thomas. Using that, we can define a "CloseBehavior" that 15 handles the code behind of starting a storyboard 14 and closing the window when it's done.
using System.ComponentModel;
using System.Windows;
using System.Windows.Interactivity;
using System.Windows.Media.Animation;
namespace Presentation.Behaviours {
public class CloseBehavior : Behavior<Window> {
public static readonly DependencyProperty StoryboardProperty =
DependencyProperty.Register("Storyboard", typeof(Storyboard), typeof(CloseBehavior), new PropertyMetadata(default(Storyboard)));
public Storyboard Storyboard {
get { return (Storyboard)GetValue(StoryboardProperty); }
set { SetValue(StoryboardProperty, value); }
}
protected override void OnAttached() {
base.OnAttached();
AssociatedObject.Closing += onWindowClosing;
}
private void onWindowClosing(object sender, CancelEventArgs e) {
if (Storyboard == null) {
return;
}
e.Cancel = true;
AssociatedObject.Closing -= onWindowClosing;
Storyboard.Completed += (o, a) => AssociatedObject.Close();
Storyboard.Begin(AssociatedObject);
}
}
}
The 13 behavior defines a storyboard as a dependency 12 property, so we can set it in xaml and when 11 the AssociatedObject
(the window where we define the behavior) is 10 closing, this storyboard is started using 9 Storyboard.Begin()
. Now, in xaml we simply add the behavior 8 to the window using the following xaml
<Window x:Class="Presentation.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:behave="clr-namespace:Presentation.Behaviours"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
x:Name="window">
<Window.Resources>
<Storyboard x:Key="ExitAnimation">
<DoubleAnimation Storyboard.Target="{Binding ElementName='window'}"
Storyboard.TargetProperty="(Window.Opacity)"
Duration="0:0:1" From="1" To="0"/>
</Storyboard>
</Window.Resources>
<i:Interaction.Behaviors>
<behave:CloseBehavior Storyboard="{StaticResource ExitAnimation}"/>
</i:Interaction.Behaviors>
<Grid>
</Grid>
</Window>
Note 7 the xml namespace i
from the System.Windows.Interactivity 6 dll, and also that the window is referenced, so 5 it has to have a x:Name
assigned. Now we simply 4 add the behavior to every window on which 3 we wish to execute a storyboard before closing 2 the application, instead of copying the 1 logic to every code-behind in each window.
I'm not an expert on WPF but I believe that 6 unless you cancel the initial Closing event 5 the window will be gone before the animation 4 is even started.
Upon receiving the Window.Closing 3 event, you should cancel the event and start 2 the animation. When the animation is done 1 you can close the window.
This is even simpler and shorter. Add a 2 behavior as follows:
public class WindowClosingBehavior : Behavior<Window>
{
protected override void OnAttached()
{
AssociatedObject.Closing += AssociatedObject_Closing;
}
private void AssociatedObject_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Window window = sender as Window;
window.Closing -= AssociatedObject_Closing;
e.Cancel = true;
var anim = new DoubleAnimation(0, (Duration)TimeSpan.FromSeconds(0.5));
anim.Completed += (s, _) => window.Close();
window.BeginAnimation(UIElement.OpacityProperty, anim);
}
protected override void OnDetaching()
{
AssociatedObject.Closing -= AssociatedObject_Closing;
}
}
Then in your window 1 add a reference :
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:wt="clr-namespace:Desktop.Themes.WindowTask;assembly=Desktop.Themes"
Insert the behavior:
<i:Interaction.Behaviors>
<wt:WindowClosingBehavior />
</i:Interaction.Behaviors>
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.