Затухание окна wpf при закрытии
Я хочу убрать окно в/из моего приложения.
Затухание происходит на Window.Loaded
, и я хотел затухать при закрытии (Window.Closed
или Window.Closing
).
Затухание в работе отлично, но Window.Closing
не допускается значение для свойства RoutedEvent
.
Что RoutedEvent
следует использовать для Close?
<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" не может быть присвоено свойству "RoutedEvent". Недопустимое имя события.
Ответы
Ответ 1
Закрытие не является маршрутизируемым событием, поэтому вы не можете использовать его в 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();
}
Ответ 2
Я думал, что добавлю другое решение, используя поведение из пакета 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
из dll System.Windows.Interactivity, а также на то, что на него ссылаются, поэтому он должен иметь назначенный x:Name
. Теперь мы просто добавляем поведение в каждое окно, в котором хотим выполнить раскадровку перед закрытием приложения, вместо того, чтобы копировать логику на каждый код в каждом окне.
Ответ 3
Я не эксперт в WPF, но я считаю, что, если вы не отмените начальное событие закрытия, окно исчезнет до начала анимации.
После получения события Window.Closing вы должны отменить событие и запустить анимацию. Когда анимация завершена, вы можете закрыть окно.
Ответ 4
Это еще проще и короче. Добавьте поведение следующим образом:
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>
Ответ 5
Установите AutoReverse To "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>