// 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; } }