using System; using Avalonia; using Avalonia.Controls; using Avalonia.Interactivity; using ReactiveUI; namespace DispenserUI.Views.Controls; /// /// 按钮 with 加载中动画 /// public class LoadingButton : Button { public static readonly StyledProperty IsLoadingProperty = AvaloniaProperty.Register(nameof(IsLoading)); private bool _isCommandExecuting; static LoadingButton() { // Register the IsLoading property to trigger a pseudo-class when it changes IsLoadingProperty.Changed.AddClassHandler((x, e) => x.UpdatePseudoClasses()); } public LoadingButton() { // Assign the default style of the button from 'LoadingButton.xaml' this.GetObservable(ContentProperty).Subscribe(_ => UpdatePseudoClasses()); ClickEvent.AddClassHandler((x, e) => x.OnDebounceClick(e), RoutingStrategies.Bubble); } public bool IsLoading { get => GetValue(IsLoadingProperty); set => SetValue(IsLoadingProperty, value); } private void UpdatePseudoClasses() { PseudoClasses.Set(":loading", IsLoading); } private void OnDebounceClick(RoutedEventArgs e) { if (Command is not IReactiveCommand command) return; if (_isCommandExecuting || Command == null) return; command.IsExecuting.Subscribe(x => { if (x) return; _isCommandExecuting = false; SetCurrentValue(IsLoadingProperty, false); e.Handled = true; }, ex => { }, () => { }); var commandParameter = CommandParameter; // 检查命令是否可以执行 if (!Command.CanExecute(commandParameter)) return; _isCommandExecuting = true; SetCurrentValue(IsLoadingProperty, true); // 执行命令 Command.Execute(commandParameter); } }