关闭时淡出 wpf 窗口
-
22-08-2019 - |
题
我想在我的应用程序中淡入/淡出窗口。
淡入发生于 Window.Loaded
我想在关闭时淡出(Window.Closed
或者 Window.Closing
)。淡入效果完美,但是 Window.Closing
不允许值为 RoutedEvent
财产。
什么 RoutedEvent
我应该用于关闭吗?
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:2" FillBehavior="HoldEnd" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Window.Closing">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1" To="0" Duration="0:0:2" FillBehavior="HoldEnd" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
我收到错误,值“Window.Closing”无法分配给属性“RoatedEvent”。事件名称无效。
解决方案
关闭不是路由事件,因此您不能在 EventTrigger 中使用它。也许您可以在代码隐藏中的 ClosingEvent 处理程序中启动故事板并取消该事件...类似的东西:
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();
}
其他提示
我想我应该添加另一个解决方案来执行此操作,使用 Expression SDK 中的行为并将其与 @Thomas 的解决方案相结合。使用它,我们可以定义一个“CloseBehavior”来处理启动故事板并在完成后关闭窗口的代码。
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);
}
}
}
该行为将故事板定义为依赖属性,因此我们可以在 xaml 中设置它,并且当 AssociatedObject
(我们定义行为的窗口)正在关闭,这个故事板开始使用 Storyboard.Begin()
. 。现在,在 xaml 中,我们只需使用以下 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>
注意 xml 命名空间 i
来自 System.Windows.Interactivity dll,并且该窗口被引用,因此它必须有一个 x:Name
分配的。现在,我们只需在关闭应用程序之前将行为添加到我们希望在其上执行故事板的每个窗口,而不是将逻辑复制到每个窗口中的每个代码隐藏中。
我不是 WPF 专家,但我相信除非您取消初始关闭事件,否则窗口将在动画开始之前消失。
收到 Window.Closing 事件后,您应该取消该事件并开始动画。动画完成后,您可以关闭窗口。
这甚至更简单、更短。添加如下行为:
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;
}
}
然后在您的窗口中添加引用:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:wt="clr-namespace:Desktop.Themes.WindowTask;assembly=Desktop.Themes"
插入行为:
<i:Interaction.Behaviors>
<wt:WindowClosingBehavior />
</i:Interaction.Behaviors>
将自动反转设置为“True”
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" AutoReverse="True" From="0" To="1" Duration="0:0:0.5" FillBehavior="HoldEnd" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>