Dispenser/DispenserUI/Views/Controls/LoadingButton.cs

68 lines
1.9 KiB
C#

using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using ReactiveUI;
namespace DispenserUI.Views.Controls;
/// <summary>
/// 按钮 with 加载中动画
/// </summary>
public class LoadingButton : Button
{
public static readonly StyledProperty<bool> IsLoadingProperty =
AvaloniaProperty.Register<LoadingButton, bool>(nameof(IsLoading));
private bool _isCommandExecuting;
static LoadingButton()
{
// Register the IsLoading property to trigger a pseudo-class when it changes
IsLoadingProperty.Changed.AddClassHandler<LoadingButton>((x, e) => x.UpdatePseudoClasses());
}
public LoadingButton()
{
// Assign the default style of the button from 'LoadingButton.xaml'
this.GetObservable(ContentProperty).Subscribe(_ => UpdatePseudoClasses());
ClickEvent.AddClassHandler<LoadingButton>((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);
}
}