WPF窗口尺寸动画问题:仅单个属性生效,第二个动画失效
WPF窗口尺寸动画切换问题解决及完整实现
问题根源
你的核心问题是Storyboard默认的FillBehavior.HoldEnd:动画结束后会把目标属性(比如Height)冻结为动画最终值,后续修改或新动画无法覆盖这个冻结状态,导致高度不更新。另外你当前的动画没有设置过渡时长,完全是瞬间跳转,也不符合“动画切换”的预期。
解决方案要点
- 给所有动画设置
FillBehavior="Stop",让动画结束后属性值恢复可修改状态 - 为动画添加合理的过渡时长,实现平滑尺寸变化
- 维护当前视图状态,实现小→中→大的循环切换逻辑
- 针对不同模式设置窗口的
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
相关产品推荐
相关产品推荐

