You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF窗口尺寸动画问题:仅单个属性生效,第二个动画失效

WPF窗口尺寸动画切换问题解决及完整实现

问题根源

你的核心问题是Storyboard默认的FillBehavior.HoldEnd:动画结束后会把目标属性(比如Height)冻结为动画最终值,后续修改或新动画无法覆盖这个冻结状态,导致高度不更新。另外你当前的动画没有设置过渡时长,完全是瞬间跳转,也不符合“动画切换”的预期。

解决方案要点

  1. 给所有动画设置FillBehavior="Stop",让动画结束后属性值恢复可修改状态
  2. 为动画添加合理的过渡时长,实现平滑尺寸变化
  3. 维护当前视图状态,实现小→中→大的循环切换逻辑
  4. 针对不同模式设置窗口的ResizeMode和尺寸限制:
    • 小模式:固定尺寸,禁止调整(ResizeMode="NoResize")
    • 中模式:仅允许调整高度,宽度固定(ResizeMode="CanResizeWithGrip" + 绑定宽度到固定值)
    • 大模式:允许自由调整宽高(ResizeMode="CanResize")

完整实现代码

XAML部分

<Window x:Class="WindowResizeAnimation.MainWindow"
        x:Name="window"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window Resize Demo" Width="80" Height="400" ResizeMode="NoResize">
    <Window.Resources>
        <!-- 小→中动画 -->
        <Storyboard x:Key="SmallToMedium">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="window" 
                                           Storyboard.TargetProperty="Width"
                                           FillBehavior="Stop">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="80"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.3" Value="450"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="window" 
                                           Storyboard.TargetProperty="Height"
                                           FillBehavior="Stop">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="400"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.3" Value="600"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

        <!-- 中→大动画 -->
        <Storyboard x:Key="MediumToLarge">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="window" 
                                           Storyboard.TargetProperty="Width"
                                           FillBehavior="Stop">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="450"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.3" Value="800"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="window" 
                                           Storyboard.TargetProperty="Height"
                                           FillBehavior="Stop">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="600"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.3" Value="800"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

        <!-- 大→小动画 -->
        <Storyboard x:Key="LargeToSmall">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="window" 
                                           Storyboard.TargetProperty="Width"
                                           FillBehavior="Stop">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="{Binding ActualWidth, ElementName=window}"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.3" Value="80"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="window" 
                                           Storyboard.TargetProperty="Height"
                                           FillBehavior="Stop">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="{Binding ActualHeight, ElementName=window}"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.3" Value="400"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>

    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Spacing="10">
        <Button Content="切换视图" Click="SwitchView_Click"/>
    </StackPanel>
</Window>

C#部分

using System.Windows;
using System.Windows.Media.Animation;

namespace WindowResizeAnimation
{
    public enum ViewMode
    {
        Small,
        Medium,
        Large
    }

    public partial class MainWindow : Window
    {
        private ViewMode _currentMode = ViewMode.Small;
        private Storyboard _smallToMedium;
        private Storyboard _mediumToLarge;
        private Storyboard _largeToSmall;

        public MainWindow()
        {
            InitializeComponent();
            LoadStoryboards();
        }

        private void LoadStoryboards()
        {
            _smallToMedium = FindResource("SmallToMedium") as Storyboard;
            _mediumToLarge = FindResource("MediumToLarge") as Storyboard;
            _largeToSmall = FindResource("LargeToSmall") as Storyboard;
        }

        private void SwitchView_Click(object sender, RoutedEventArgs e)
        {
            // 先停止所有可能正在运行的动画
            _smallToMedium.Stop(this);
            _mediumToLarge.Stop(this);
            _largeToSmall.Stop(this);

            switch (_currentMode)
            {
                case ViewMode.Small:
                    _smallToMedium.Begin(this, true);
                    _currentMode = ViewMode.Medium;
                    // 中模式:仅允许调整高度,宽度固定
                    ResizeMode = ResizeMode.CanResizeWithGrip;
                    window.Width = 450;
                    window.MinWidth = 450;
                    window.MaxWidth = 450;
                    break;
                case ViewMode.Medium:
                    _mediumToLarge.Begin(this, true);
                    _currentMode = ViewMode.Large;
                    // 大模式:允许自由调整
                    ResizeMode = ResizeMode.CanResize;
                    window.MinWidth = 450;
                    window.MinHeight = 600;
                    window.MaxWidth = double.PositiveInfinity;
                    window.MaxHeight = double.PositiveInfinity;
                    break;
                case ViewMode.Large:
                    _largeToSmall.Begin(this, true);
                    _currentMode = ViewMode.Small;
                    // 小模式:固定尺寸,禁止调整
                    ResizeMode = ResizeMode.NoResize;
                    window.MinWidth = 80;
                    window.MaxWidth = 80;
                    window.MinHeight = 400;
                    window.MaxHeight = 400;
                    break;
            }
        }
    }
}

关键说明

  • 所有动画都添加了FillBehavior="Stop",避免属性值被冻结
  • 大→小动画的起始值绑定到窗口当前实际尺寸,适配用户在大模式下调整后的尺寸
  • 通过ViewMode枚举维护当前状态,实现循环切换逻辑
  • 针对不同模式设置ResizeMode和宽高的最小/最大值,实现对应的尺寸控制规则

内容的提问来源于stack exchange,提问作者Boppity Bop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:02:50