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

WinUI 3中如何为执行命令后的按钮添加临时动画?

解决方案

不用从头设计Button样式,直接在C#代码中通过Storyboard实现临时动画,完全保留Button默认行为:

1. 修改ConfirmButton类代码

替换原有的C#实现,通过代码创建动画并自动恢复状态:

using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Animation;

namespace BridgeSystems.Framework.WinUI.Controls;

public class ConfirmButton : Button
{
    public bool HasBeenExecuted
    {
        get => (bool)GetValue(HasBeenExecutedProperty);
        set => SetValue(HasBeenExecutedProperty, value);
    }

    public static readonly DependencyProperty HasBeenExecutedProperty =
        DependencyProperty.Register(nameof(HasBeenExecuted), typeof(bool), typeof(ConfirmButton), new PropertyMetadata(false, OnHasBeenExecutedChanged));

    private static void OnHasBeenExecutedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var button = d as ConfirmButton;
        if (button == null || !(bool)e.NewValue) return;

        button.StartConfirmationAnimation();
        // 动画结束后重置状态
        button.DispatcherQueue.TryEnqueue(async () =>
        {
            await Task.Delay(2000); // 与动画总时长保持一致
            button.HasBeenExecuted = false;
        });
    }

    private void StartConfirmationAnimation()
    {
        // 缓存当前属性值
        var originalBackground = Background;
        var originalForeground = Foreground;
        var originalFontSize = FontSize;

        // 快速切换到确认状态的动画
        var bgAnim = new ColorAnimation
        {
            To = Colors.Green,
            Duration = TimeSpan.FromMilliseconds(100),
            FillBehavior = FillBehavior.HoldEnd
        };
        Storyboard.SetTarget(bgAnim, this);
        Storyboard.SetTargetProperty(bgAnim, "(Button.Background).(SolidColorBrush.Color)");

        var fgAnim = new ColorAnimation
        {
            To = Colors.White,
            Duration = TimeSpan.FromMilliseconds(100),
            FillBehavior = FillBehavior.HoldEnd
        };
        Storyboard.SetTarget(fgAnim, this);
        Storyboard.SetTargetProperty(fgAnim, "(Button.Foreground).(SolidColorBrush.Color)");

        var fontSizeAnim = new DoubleAnimation
        {
            To = 20,
            Duration = TimeSpan.FromMilliseconds(100),
            FillBehavior = FillBehavior.HoldEnd
        };
        Storyboard.SetTarget(fontSizeAnim, this);
        Storyboard.SetTargetProperty(fontSizeAnim, "FontSize");

        // 延迟恢复到原始状态的动画
        var bgResetAnim = new ColorAnimation
        {
            To = ((SolidColorBrush)originalBackground).Color,
            BeginTime = TimeSpan.FromSeconds(1.9),
            Duration = TimeSpan.FromMilliseconds(100),
            FillBehavior = FillBehavior.Stop
        };
        Storyboard.SetTarget(bgResetAnim, this);
        Storyboard.SetTargetProperty(bgResetAnim, "(Button.Background).(SolidColorBrush.Color)");

        var fgResetAnim = new ColorAnimation
        {
            To = ((SolidColorBrush)originalForeground).Color,
            BeginTime = TimeSpan.FromSeconds(1.9),
            Duration = TimeSpan.FromMilliseconds(100),
            FillBehavior = FillBehavior.Stop
        };
        Storyboard.SetTarget(fgResetAnim, this);
        Storyboard.SetTargetProperty(fgResetAnim, "(Button.Foreground).(SolidColorBrush.Color)");

        var fontSizeResetAnim = new DoubleAnimation
        {
            To = originalFontSize,
            BeginTime = TimeSpan.FromSeconds(1.9),
            Duration = TimeSpan.FromMilliseconds(100),
            FillBehavior = FillBehavior.Stop
        };
        Storyboard.SetTarget(fontSizeResetAnim, this);
        Storyboard.SetTargetProperty(fontSizeResetAnim, "FontSize");

        // 组装并启动动画
        var storyboard = new Storyboard();
        storyboard.Children.Add(bgAnim);
        storyboard.Children.Add(fgAnim);
        storyboard.Children.Add(fontSizeAnim);
        storyboard.Children.Add(bgResetAnim);
        storyboard.Children.Add(fgResetAnim);
        storyboard.Children.Add(fontSizeResetAnim);

        // 保险:动画结束后强制恢复原始属性
        storyboard.Completed += (_, __) =>
        {
            Background = originalBackground;
            Foreground = originalForeground;
            FontSize = originalFontSize;
        };

        storyboard.Begin();
    }
}

2. 使用方式

  • 命令执行时,只需将HasBeenExecuted设为true即可触发动画:
    // 示例:Command的Executed事件处理
    private void MyCustomCommand_Executed(object sender, ExecutedRoutedEventArgs e)
    {
        // 执行业务逻辑
        confirmButton.HasBeenExecuted = true;
    }
    
  • 也可以通过数据绑定关联ViewModel中的HasExecuted属性:
    <local:ConfirmButton Command="{Binding MyCommand}" HasBeenExecuted="{Binding HasExecuted}"/>
    

关键点说明

  • 完全保留Button的默认样式与交互行为(点击、悬停、聚焦等状态不受影响)
  • 动画总时长2秒(100ms切换到绿色状态,保持1.8秒,100ms恢复原状),可通过修改Task.Delay和BeginTime参数调整时长
  • 兼容纯色背景场景,若需支持渐变背景,可修改动画目标属性或添加类型判断逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 20:34:54