WPF按钮根据命令执行结果实现样式切换与动画效果
WPF ListView保存按钮样式切换与命令逻辑分离方案
一、抽离保存命令逻辑
创建独立的SaveCommand类实现ICommand,将保存逻辑完全从ItemViewModel中剥离,仅依赖ISettingsManager、配置数据和结果回调:
public class SaveCommand : ICommand { public enum SaveResult { None, Success, Failure } private readonly ISettingsManager _settingsManager; private readonly object _configData; private readonly Action<SaveResult> _onSaveCompleted; public SaveCommand(ISettingsManager settingsManager, object configData, Action<SaveResult> onSaveCompleted) { _settingsManager = settingsManager; _configData = configData; _onSaveCompleted = onSaveCompleted; } public bool CanExecute(object parameter) => true; // 若ISettingsManager.Save为同步方法,移除async/await即可 public async void Execute(object parameter) { try { await _settingsManager.Save(_configData); _onSaveCompleted?.Invoke(SaveResult.Success); } catch (Exception) { _onSaveCompleted?.Invoke(SaveResult.Failure); } } public event EventHandler CanExecuteChanged; }
二、调整ItemViewModel职责
ItemViewModel仅维护保存结果状态,不包含命令逻辑,通过构造函数注入依赖并创建命令:
public class ItemViewModel : INotifyPropertyChanged { private SaveCommand.SaveResult _saveResult = SaveCommand.SaveResult.None; public SaveCommand.SaveResult SaveResult { get => _saveResult; set { _saveResult = value; OnPropertyChanged(); } } public ICommand SaveCommand { get; } public ItemViewModel(ISettingsManager settingsManager, YourConfigType configData) { SaveCommand = new SaveCommand(settingsManager, configData, result => { SaveResult = result; // 可选:2秒后重置状态,按钮自动恢复默认样式 Task.Delay(2000).ContinueWith(_ => SaveResult = SaveCommand.SaveResult.None); }); } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
三、ItemView中绑定样式与命令
在列表项的XAML中,通过DataTrigger根据SaveResult切换按钮样式,并添加动画效果:
<Button Content="保存" Command="{Binding SaveCommand}"> <Button.Style> <Style TargetType="Button"> <!-- 默认样式 --> <Setter Property="Background" Value="#FF0078D7"/> <Setter Property="Foreground" Value="White"/> <Setter Property="Padding" Value="8,4"/> <Setter Property="BorderThickness" Value="0"/> <Style.Triggers> <!-- 成功状态样式与动画 --> <DataTrigger Binding="{Binding SaveResult}" Value="Success"> <Setter Property="Background" Value="#FF00B248"/> <DataTrigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.6" To="1" Duration="0:0:0.3"/> </Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> </DataTrigger> <!-- 失败状态样式与动画 --> <DataTrigger Binding="{Binding SaveResult}" Value="Failure"> <Setter Property="Background" Value="#FFE81123"/> <DataTrigger.EnterActions> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.6" To="1" Duration="0:0:0.3"/> <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" From="0.9" To="1.1" RepeatBehavior="3x" AutoReverse="True" Duration="0:0:0.1"/> <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" From="0.9" To="1.1" RepeatBehavior="3x" AutoReverse="True" Duration="0:0:0.1"/> </Storyboard> </BeginStoryboard> </DataTrigger.EnterActions> </DataTrigger> </Style.Triggers> </Style> </Button.Style> <Button.RenderTransform> <ScaleTransform/> </Button.RenderTransform> </Button>
四、核心说明
- 命令逻辑完全独立,
ItemViewModel仅承担状态维护职责,符合单一原则。 - 通过
SaveResult枚举作为绑定源,实现样式与业务逻辑的解耦。 - 可根据需求调整动画效果或状态重置延迟时间,优化用户体验。
内容的提问来源于stack exchange,提问作者Dungeoner
相关产品推荐
相关产品推荐

