WPF窗口动画.顶部停在不同的值

本文关键字:窗口 动画 顶部 WPF | 更新日期: 2023-09-27 18:08:10

我构建了一个类似"windows 8开始菜单"的应用程序。我使用动画将菜单窗口从底部滑动到屏幕上。动画使用窗口。

但是每次我运行应用程序时,

中Top的值
wAnimation.Completed += (s1, e1) =>
                {
                    SizeChanged += (s2, e2) => { if (e2.HeightChanged) Top = businessLogic.CalculateWindowTopLeft(Width, Height).Y; };
                };
当(仔细阅读!)我在"SizeChanged"-Line上设置了断点时,

在~5到~15点之间抖动。这意味着在"商业逻辑"之前。CalculateWindowTopLeft"被执行。这意味着,我看到的"Top"是动画顶部的最终值。

他到底为什么要这么做?这是一个奇怪的W32/WPF/wHandle bug吗?我不理解这种行为。

Extra-Comment:

首先,我有动画代码在xaml和绑定它(像你通常做的)。为了调试,我已经在代码后面这样做了(见下文)。我也尝试(见下文)设置动画发生后的绑定,使绑定不能做错误的事情。这些行为在所有情况下都是完全相同的(错误的)。

告诉我,如果你还需要xaml代码,那么我就把它贴出来。

(对不起,我的英语不好,我是一个德国人)。

public MainWindow()
    {
        Visibility = Visibility.Hidden;
        InitializeComponent();
        businessLogic = new BusinessLogic(new DataModel(), new DataPersister());
        var vm = new MainWindowViewModel(businessLogic, new DialogService());
        DataContext = vm;
        businessLogic.Load();
        Width = businessLogic.DataModel.MenuWidth;
        Height = businessLogic.DataModel.MenuHeight;
        Opacity = 0;
        windowPosition = businessLogic.CalculateWindowTopLeft(Width, Height);
        Top = SystemParameters.PrimaryScreenHeight - (Height * 0.50);
        //Top = windowPosition.Y;
        Left = windowPosition.X;
        Background = businessLogic.GetTaskBarPreviewSolidColorBrush(1);
        vm.CloseRequested += (s) => Hide();
        Deactivated += (s, e) => { if (!vm.SettingsOpened) Close(); };
        Loaded += (s, e) =>
        {
            var wAnimation = new System.Windows.Media.Animation.DoubleAnimation(windowPosition.Y, new Duration(new TimeSpan(0, 0, 0, 0, 300)));
            wAnimation.FillBehavior = System.Windows.Media.Animation.FillBehavior.Stop;
            wAnimation.AccelerationRatio = 0.1;
            wAnimation.From = Top;
            wAnimation.Completed += (s1, e1) =>
                {
                    SizeChanged += (s2, e2) => { if (e2.HeightChanged) Top = businessLogic.CalculateWindowTopLeft(Width, Height).Y; };
                };
            var oAnimation = new System.Windows.Media.Animation.DoubleAnimation(businessLogic.DataModel.MenuOpacity, new Duration(new TimeSpan(0, 0, 0, 0, 600)));
            oAnimation.FillBehavior = System.Windows.Media.Animation.FillBehavior.Stop;
            oAnimation.AccelerationRatio = 0.1;
            oAnimation.From = 0;
            oAnimation.Completed += (s3, e3) =>
            {
                Binding myBinding = new Binding();
                myBinding.Source = DataContext;
                myBinding.Path = new PropertyPath("DataModel.MenuOpacity");
                myBinding.Mode = BindingMode.TwoWay;
                myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                BindingOperations.SetBinding(this, Window.OpacityProperty, myBinding);
            };
            BeginAnimation(Window.TopProperty, wAnimation);
            BeginAnimation(Window.OpacityProperty, oAnimation);
        };
        Visibility = Visibility.Visible;
    }
}

}

WPF窗口动画.顶部停在不同的值

有趣的…

这个非常(!)简单的代码创建了完全相同的行为。开始10次,你就明白我的意思了。我不敢相信……:)

namespace SlideTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            Deactivated += (s, e) => Close();
        }
    }
}
<Window x:Class="SlideTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="400" Width="200" Top="500" Left="700"
    WindowStyle="None" AllowsTransparency="True" Background="Aqua">
<Window.Triggers>
    <EventTrigger RoutedEvent="Window.Loaded">
        <BeginStoryboard>
            <Storyboard Duration="00:00:.30">
                <DoubleAnimation Duration="00:00:.30" AccelerationRatio="0.1" Storyboard.TargetProperty="Top" From="1400" To="455" FillBehavior="Stop"></DoubleAnimation>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Window.Triggers>

我找到了一个解决方案。不是很好,但这是唯一有效的方法。我永远不会理解"填充行为=停止"的行为。对我来说,这似乎是一个bug(即使我不能相信)或一些奇怪的深层"wpf动画的本质"的东西…

那么,我们开始:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Deactivated += (s, e) => Close();
        myAnimation.Completed += (s, e) =>
            {
                this.BeginAnimation(Window.TopProperty, null);
                myStoryboard.Remove();
            };
    }
}
<Window x:Class="SlideTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="400" Width="200" Top="455" Left="700"
    WindowStyle="None" AllowsTransparency="True" Background="Aqua">
<Window.Triggers>
    <EventTrigger RoutedEvent="Window.Loaded">
        <BeginStoryboard>
            <Storyboard Duration="00:00:.30" Name="myStoryboard">
                <DoubleAnimation Duration="00:00:.30" AccelerationRatio="0.1" Storyboard.TargetProperty="Top" From="1400" To="455" FillBehavior="HoldEnd" Name="myAnimation"></DoubleAnimation>
            </Storyboard>
        </BeginStoryboard>
    </EventTrigger>
</Window.Triggers>