C# 在关闭时淡出 wpf 窗口

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/867656/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 04:52:11  来源:igfitidea点击:

Fading out a wpf window on close

c#wpfanimationeventtriggerroutedevent

提问by James

I want to fade a window in/out in my application.
Fading in occurs on Window.Loadedand I wanted to fade out on close (Window.Closedor Window.Closing). Fading in works perfectly, but Window.Closingis not allowed value for RoutedEventproperty.
What RoutedEventshould I be using for Close?

我想在我的应用程序中淡入/淡出一个窗口。
淡入发生在Window.Loaded,我想在关闭(Window.ClosedWindow.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>

I get a error on , Value 'Window.Closing' cannot be assigned to property 'RoutedEvent'. Invalid event name.

我收到一个错误,值 'Window.Closing' 不能分配给属性 'RoutedEvent'。无效的事件名称。

采纳答案by Thomas Levesque

Closing is not a routed event, so you can't use it in an EventTrigger. Perhaps you could start the storyboard in the handler of the ClosingEvent in the code-behind and cancel the event... something like that :

关闭不是路由事件,因此您不能在 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();
}

回答by Peter Lillevold

I'm not an expert on WPF but I believe that unless you cancel the initial Closing event the window will be gone before the animation is even started.

我不是 WPF 方面的专家,但我相信除非您取消初始 Closing 事件,否则窗口将在动画开始之前消失。

Upon receiving the Window.Closing event, you should cancel the event and start the animation. When the animation is done you can close the window.

收到 Window.Closing 事件后,您应该取消该事件并启动动画。动画完成后,您可以关闭窗口。

回答by Patrick

I thought I'd add another solution of doing this, using behaviors from the Expression SDK and combining it with the solution from @Thomas. Using that, we can define a "CloseBehavior" that handles the code behind of starting a storyboard and closing the window when it's done.

我想我会添加另一个解决方案,使用来自 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);
        }
    }
}

The behavior defines a storyboard as a dependency property, so we can set it in xaml and when the AssociatedObject(the window where we define the behavior) is closing, this storyboard is started using Storyboard.Begin(). Now, in xaml we simply add the behavior to the window using the following xaml

该行为将故事板定义为依赖属性,因此我们可以在 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>

Note the xml namespace ifrom the System.Windows.Interactivity dll, and also that the window is referenced, so it has to have a x:Nameassigned. Now we simply add the behavior to every window on which we wish to execute a storyboard before closing the application, instead of copying the logic to every code-behind in each window.

请注意iSystem.Windows.Interactivity dll 中的 xml 命名空间,并且还引用了该窗口,因此必须为其x:Name分配一个。现在,我们只需在关闭应用程序之前将行为添加到我们希望在其上执行故事板的每个窗口,而不是将逻辑复制到每个窗口中的每个代码隐藏中。

回答by nadjibnet

Set 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>

回答by Nandy

This is even simpler and shorter. Add a 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 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>