VPet/VPet.Solution/SimpleObservable/ObservableCommand/ObservableCommand.cs
2023-12-18 22:53:56 +08:00

116 lines
3.2 KiB
C#

using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Input;
namespace HKW.HKWUtils.Observable;
/// <summary>
/// 可观察命令
/// </summary>
[DebuggerDisplay("\\{ObservableCommand, CanExecute = {IsCanExecute.Value}\\}")]
public class ObservableCommand : ObservableClass<ObservableCommand>, ICommand
{
bool _isCanExecute = true;
/// <summary>
/// 能执行的属性
/// </summary>
public bool IsCanExecute
{
get => _isCanExecute;
set => SetProperty(ref _isCanExecute, value);
}
bool _currentCanExecute = true;
/// <summary>
/// 当前可执行状态
/// <para>
/// 在执行异步事件时会强制为 <see langword="false"/>, 但异步结束后会恢复为 <see cref="IsCanExecute"/> 的值
/// </para>
/// </summary>
public bool CurrentCanExecute
{
get => _currentCanExecute;
private set => SetProperty(ref _currentCanExecute, value);
}
/// <inheritdoc/>
public ObservableCommand()
{
PropertyChanged += OnCanExecuteChanged;
}
private void OnCanExecuteChanged(object? sender, PropertyChangedEventArgs e)
{
CanExecuteChanged?.Invoke(this, new());
}
#region ICommand
/// <summary>
/// 能否被执行
/// </summary>
/// <param name="parameter">参数</param>
/// <returns>能被执行为 <see langword="true"/> 否则为 <see langword="false"/></returns>
public bool CanExecute(object? parameter)
{
return CurrentCanExecute && IsCanExecute;
}
/// <summary>
/// 执行方法
/// </summary>
/// <param name="parameter">参数</param>
public async void Execute(object? parameter)
{
if (IsCanExecute is not true)
return;
ExecuteCommand?.Invoke();
await ExecuteAsync();
}
/// <summary>
/// 执行异步方法, 会在等待中修改 <see cref="CurrentCanExecute"/>, 完成后恢复
/// <para>
/// 若要在执行此方法时触发 <see cref="ExecuteCommand"/> 事件, 请将 <paramref name="runAlone"/> 设置为 <see langword="true"/>
/// </para>
/// </summary>
/// <param name="runAlone">设置为 <see langword="true"/> 时触发 <see cref="ExecuteCommand"/> 事件</param>
/// <returns>任务</returns>
public async Task ExecuteAsync(bool runAlone = false)
{
if (IsCanExecute is not true)
return;
if (runAlone)
ExecuteCommand?.Invoke();
if (ExecuteAsyncCommand is null)
return;
CurrentCanExecute = false;
foreach (
var asyncEvent in ExecuteAsyncCommand
.GetInvocationList()
.Cast<ExecuteAsyncEventHandler>()
)
await asyncEvent.Invoke();
CurrentCanExecute = true;
}
#endregion
#region Event
/// <summary>
/// 能否执行属性改变后事件
/// </summary>
public event EventHandler? CanExecuteChanged;
/// <summary>
/// 执行事件
/// </summary>
public event ExecuteEventHandler? ExecuteCommand;
/// <summary>
/// 异步执行事件
/// </summary>
public event ExecuteAsyncEventHandler? ExecuteAsyncCommand;
#endregion
}