// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System;
using System.Windows.Input;
namespace CommunityToolkit.Mvvm.Input;
///
/// An attribute that can be used to automatically generate properties from declared methods. When this attribute
/// is used to decorate a method, a generator will create a command property with the corresponding interface
/// depending on the signature of the method. If an invalid method signature is used, the generator will report an error.
///
/// In order to use this attribute, the containing type doesn't need to implement any interfaces. The generated properties will be lazily
/// assigned but their value will never change, so there is no need to support property change notifications or other additional functionality.
///
///
/// This attribute can be used as follows:
///
/// partial class MyViewModel
/// {
/// [RelayCommand]
/// private void GreetUser(User? user)
/// {
/// Console.WriteLine($"Hello {user.Name}!");
/// }
/// }
///
/// And with this, code analogous to this will be generated:
///
/// partial class MyViewModel
/// {
/// private RelayCommand? greetUserCommand;
///
/// public IRelayCommand GreetUserCommand => greetUserCommand ??= new RelayCommand(GreetUser);
/// }
///
///
///
/// The following signatures are supported for annotated methods:
///
/// void Method();
///
/// Will generate an property (using a instance).
///
/// void Method(T?);
///
/// Will generate an property (using a instance).
///
/// Task Method();
/// Task Method(CancellationToken);
/// Task<T> Method();
/// Task<T> Method(CancellationToken);
///
/// Will both generate an property (using an instance).
///
/// Task Method(T?);
/// Task Method(T?, CancellationToken);
/// Task<T> Method(T?);
/// Task<T> Method(T?, CancellationToken);
///
/// Will both generate an property (using an instance).
///
///
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public sealed class RelayCommandAttribute : Attribute
{
///
/// Gets or sets the name of the property or method that will be invoked to check whether the
/// generated command can be executed at any given time. The referenced member needs to return
/// a value, and has to have a signature compatible with the target command.
///
public string? CanExecute { get; init; }
///
/// Gets or sets a value indicating whether or not to allow concurrent executions for an asynchronous command.
///
/// When set for an attribute used on a method that would result in an or an
/// property to be generated, this will modify the behavior of these commands
/// when an execution is invoked while a previous one is still running. It is the same as creating an instance of
/// these command types with a constructor such as
/// and using the value.
///
///
/// Using this property is not valid if the target command doesn't map to an asynchronous command.
public bool AllowConcurrentExecutions { get; init; }
///
/// Gets or sets a value indicating whether or not to exceptions should be propagated to .
///
/// When set for an attribute used on a method that would result in an or an
/// property to be generated, this will modify the behavior of these commands
/// in case an exception is thrown by the underlying operation. It is the same as creating an instance of
/// these command types with a constructor such as
/// and using the value.
///
///
/// Using this property is not valid if the target command doesn't map to an asynchronous command.
public bool FlowExceptionsToTaskScheduler { get; init; }
///
/// Gets or sets a value indicating whether a cancel command should also be generated for an asynchronous command.
///
/// When set to , this additional code will be generated:
///
/// partial class MyViewModel
/// {
/// private ICommand? loginUserCancelCommand;
///
/// public ICommand LoginUserCancelCommand => loginUserCancelCommand ??= LoginUserCommand.CreateCancelCommand();
/// }
///
/// Where LoginUserCommand is an defined in the class (or generated by this attribute as well).
///
///
/// Using this property is not valid if the target command doesn't map to a cancellable asynchronous command.
public bool IncludeCancelCommand { get; init; }
}