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

WinUI3中点击Lottie动画图标触发播放及MVVM绑定问题

WinUI3 Lottie动画图标MVVM解决方案

问题1:点击图标自身触发动画

将AnimatedVisualPlayer作为Button的Content,利用Button的点击区域覆盖图标,同时通过自定义Button样式去除默认边框、背景,让它看起来就是纯图标:

<Button Width="48" Height="48" Style="{StaticResource IconButtonStyle}">
    <controls:AnimatedVisualPlayer x:Name="CreateFilePlayer" AutoPlay="False">
        <lottie:LottieVisualSource Uri="ms-appx:///AnimatedVisuals/CreateFile.json" />
    </controls:AnimatedVisualPlayer>
</Button>

对应的IconButtonStyle示例:

<Style x:Key="IconButtonStyle" TargetType="Button">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Padding" Value="4"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <ContentPresenter 
                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                    Margin="{TemplateBinding Padding}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

问题2:绑定ViewModel的Command

直接给包裹图标的Button绑定ViewModel中的CreateFileCommand,同时可以结合动画触发逻辑:

方案1:少量代码后置(仅处理动画播放)

XAML:

<Button Command="{x:Bind ViewModel.CreateFileCommand}" 
        Click="AnimatedIconButton_Click"
        Width="48" Height="48" Style="{StaticResource IconButtonStyle}">
    <controls:AnimatedVisualPlayer x:Name="CreateFilePlayer" AutoPlay="False">
        <lottie:LottieVisualSource Uri="ms-appx:///AnimatedVisuals/CreateFile.json" />
    </controls:AnimatedVisualPlayer>
</Button>

代码后置(仅播放动画,无业务逻辑):

private async void AnimatedIconButton_Click(object sender, RoutedEventArgs e)
{
    if ((sender as Button)?.Content is AnimatedVisualPlayer player)
    {
        await player.PlayAsync(fromProgress: 0, toProgress: 1, looped: false);
    }
}

方案2:纯MVVM无代码后置

通过自定义附加属性,绑定ViewModel的状态属性来触发动画:

  1. 创建附加属性类:
public static class AnimatedPlayerTrigger
{
    public static readonly DependencyProperty PlayAnimationProperty =
        DependencyProperty.RegisterAttached(
            "PlayAnimation", 
            typeof(bool), 
            typeof(AnimatedPlayerTrigger),
            new PropertyMetadata(false, OnPlayAnimationChanged));

    public static bool GetPlayAnimation(DependencyObject obj)
        => (bool)obj.GetValue(PlayAnimationProperty);

    public static void SetPlayAnimation(DependencyObject obj, bool value)
        => obj.SetValue(PlayAnimationProperty, value);

    private static async void OnPlayAnimationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d is AnimatedVisualPlayer player && (bool)e.NewValue)
        {
            await player.PlayAsync(0, 1, false);
            // 播放完成后重置状态,避免重复触发
            SetPlayAnimation(player, false);
        }
    }
}
  1. ViewModel中添加状态属性,在Command执行时触发:
private bool _isCreateFileAnimationPlaying;
public bool IsCreateFileAnimationPlaying
{
    get => _isCreateFileAnimationPlaying;
    set => SetProperty(ref _isCreateFileAnimationPlaying, value);
}

public ICommand CreateFileCommand => new RelayCommand(async () =>
{
    // 执行创建文件业务逻辑
    await ExecuteCreateFile();
    // 触发动画
    IsCreateFileAnimationPlaying = true;
});
  1. XAML中绑定附加属性:
<Button Command="{x:Bind ViewModel.CreateFileCommand}"
        Width="48" Height="48" Style="{StaticResource IconButtonStyle}">
    <controls:AnimatedVisualPlayer 
        local:AnimatedPlayerTrigger.PlayAnimation="{x:Bind ViewModel.IsCreateFileAnimationPlaying, Mode=TwoWay}"
        AutoPlay="False">
        <lottie:LottieVisualSource Uri="ms-appx:///AnimatedVisuals/CreateFile.json" />
    </controls:AnimatedVisualPlayer>
</Button>

问题3:MVVM模式下触发动画(减少后置代码)

上面的纯MVVM方案已经实现了无代码后置的动画触发。如果需要在样式中复用,可以将附加属性整合到Button样式里:

<Style x:Key="AnimatedIconButtonStyle" TargetType="Button">
    <Setter Property="Width" Value="48"/>
    <Setter Property="Height" Value="48"/>
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <controls:AnimatedVisualPlayer 
                    local:AnimatedPlayerTrigger.PlayAnimation="{Binding PlayAnimation, RelativeSource={RelativeSource TemplatedParent}}"
                    AutoPlay="False">
                    <lottie:LottieVisualSource Uri="{Binding AnimationUri, RelativeSource={RelativeSource TemplatedParent}}" />
                </controls:AnimatedVisualPlayer>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

使用时只需绑定Command和对应的ViewModel属性:

<Button Style="{StaticResource AnimatedIconButtonStyle}"
        Command="{x:Bind ViewModel.CreateFileCommand}"
        local:AnimatedPlayerTrigger.PlayAnimation="{x:Bind ViewModel.IsCreateFileAnimationPlaying, Mode=TwoWay}"
        Tag="ms-appx:///AnimatedVisuals/CreateFile.json" />

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:33:09