Open sandboxFocusImprove this doc

LAMA5202: The can-execute property of a command should be public

Severity Warning
Reported by Metalama.Patterns.Wpf
Message The can-execute property of the command method '<Method>' is not public, but INotifyPropertyChanged integration is enabled. Because INotifyPropertyChanged implementations usually raise the PropertyChanged event only for public properties, the CanExecuteChanged event of the command might not be raised. Make the property public or disable INotifyPropertyChanged integration.

Cause

When the CanExecute logic of a [Command] method is a property, and the declaring type implements INotifyPropertyChanged, the aspect subscribes to the PropertyChanged event and raises the command's CanExecuteChanged event when the can-execute property changes. This integration is enabled by default.

Many INotifyPropertyChanged implementations raise PropertyChanged only for public properties. If the can-execute property is private, protected, or internal, the command might never learn that the property changed, and the bound button stays enabled or disabled.

Metalama reports LAMA5202 on the can-execute property when all the following conditions are true:

  • the can-execute member found for the command, by naming convention or with CanExecuteProperty, is a property, not a method;
  • INotifyPropertyChanged integration is enabled;
  • the declaring type implements INotifyPropertyChanged;
  • the property isn't public.

In the message, <Method> is the method to which [Command] is applied. The command is still generated, and the integration is still in place.

In the following example, the command named Save uses the private property IsSaveEnabled as its can-execute property, found by the naming convention, in a type that implements INotifyPropertyChanged.

Source Code
1using Metalama.Patterns.Wpf;
2using System.ComponentModel;
3
4namespace Doc.LAMA5202.Error;
5
6public partial class DocumentViewModel : INotifyPropertyChanged
7{
8    private bool _isDirty = true;
9
10    public event PropertyChangedEventHandler? PropertyChanged;
11
12    // Warning: the can-execute property is not public.
    Warning LAMA5202: The can-execute property of the command method 'DocumentViewModel.Save()' is not public, but INotifyPropertyChanged integration is enabled. Because INotifyPropertyChanged implementations usually raise the PropertyChanged event only for public properties, the CanExecuteChanged event of the command might not be raised. Make the property public or disable INotifyPropertyChanged integration.

13    private bool IsSaveEnabled => this._isDirty;
14
15    [Command]
16    public void Save() => this._isDirty = false;
17}
18
Transformed Code
1using Metalama.Patterns.Wpf;
2using System.ComponentModel;
3
4namespace Doc.LAMA5202.Error;
5
6public partial class DocumentViewModel : INotifyPropertyChanged
7{
8    private bool _isDirty = true;
9
10    public event PropertyChangedEventHandler? PropertyChanged;
11
12    // Warning: the can-execute property is not public.
13    private bool IsSaveEnabled => this._isDirty;
14
15    [Command]
16    public void Save() => this._isDirty = false;
17
18    public DocumentViewModel()
19    {
20        SaveCommand = DelegateCommandFactory.CreateDelegateCommand(Save, () => IsSaveEnabled, this, "IsSaveEnabled");
21    }
22
23    public DelegateCommand SaveCommand { get; }
24}
25

Resolution

In the following example, the can-execute property is public.

Source Code
1using Metalama.Patterns.Wpf;
2using System.ComponentModel;
3
4namespace Doc.LAMA5202.Fixed;
5
6public partial class DocumentViewModel : INotifyPropertyChanged
7{
8    private bool _isDirty = true;
9
10    public event PropertyChangedEventHandler? PropertyChanged;
11
12    // Fixed: the can-execute property is public.
13    public bool IsSaveEnabled => this._isDirty;
14
15    [Command]
16    public void Save() => this._isDirty = false;
17}
18
Transformed Code
1using Metalama.Patterns.Wpf;
2using System.ComponentModel;
3
4namespace Doc.LAMA5202.Fixed;
5
6public partial class DocumentViewModel : INotifyPropertyChanged
7{
8    private bool _isDirty = true;
9
10    public event PropertyChangedEventHandler? PropertyChanged;
11
12    // Fixed: the can-execute property is public.
13    public bool IsSaveEnabled => this._isDirty;
14
15    [Command]
16    public void Save() => this._isDirty = false;
17
18    public DocumentViewModel()
19    {
20        SaveCommand = DelegateCommandFactory.CreateDelegateCommand(Save, () => IsSaveEnabled, this, "IsSaveEnabled");
21    }
22
23    public DelegateCommand SaveCommand { get; }
24}
25

See also