| Severity | Error |
| Reported by | Metalama.Patterns.Observability |
| Message | Class '<Class>' implements INotifyPropertyChanged but neither defines nor inherits a method with the signature 'protected void OnPropertyChanged(string)', which the [Observable] aspect requires to raise notifications. The method name can also be NotifyOfPropertyChange or RaisePropertyChanged. |
Cause
When you apply the [Observable] aspect to a class that already implements the PropertyChanged event, typically because it derives from a base view-model class, the aspect doesn't introduce its own event. Instead, it relies on two methods of the existing implementation:
- a non-static
publicorprotectedmethod returningvoidwith a singlestringparameter, which the aspect calls to raise notifications; - a
virtualmethod taking astringor a PropertyChangedEventArgs, which the aspect overrides to react to notifications raised by the base class.
These methods can be named OnPropertyChanged, NotifyOfPropertyChange, or RaisePropertyChanged, and they can be inherited.
Metalama reports LAMA5156 when the class has the overridable method but not the method taking a string. A method that has no parameter or more than one parameter is ignored. When the overridable method is missing too, Metalama reports LAMA5150 instead.
In the following example, the base class only provides OnPropertyChanged( PropertyChangedEventArgs ).
1using Metalama.Patterns.Observability;
2using System.ComponentModel;
3
4namespace Doc.LAMA5156.Error;
5
6public abstract class ViewModelBase : INotifyPropertyChanged
7{
8 public event PropertyChangedEventHandler? PropertyChanged;
9
10 // The only OnPropertyChanged method takes a PropertyChangedEventArgs.
11 protected virtual void OnPropertyChanged( PropertyChangedEventArgs args )
12 {
13 this.PropertyChanged?.Invoke( this, args );
14 }
15}
16
17// Error: no OnPropertyChanged(string) method can raise the notifications.
18[Observable]
Error LAMA5156: Class 'CustomerViewModel' implements INotifyPropertyChanged but neither defines nor inherits a method with the signature 'protected void OnPropertyChanged(string)', which the [Observable] aspect requires to raise notifications. The method name can also be NotifyOfPropertyChange or RaisePropertyChanged.
19public partial class CustomerViewModel : ViewModelBase
20{
21 public string? Name { get; set; }
22}
23
Resolution
Add a method with the signature protected void OnPropertyChanged( string propertyName ) to the class or to its base class. It can simply call the existing method, as in the following example.
Alternatively, change the parameter of the existing virtual method to string: a single protected virtual void OnPropertyChanged( string propertyName ) method satisfies both requirements.
1using Metalama.Patterns.Observability;
2using System.ComponentModel;
3
4namespace Doc.LAMA5156.Fixed;
5
6public abstract class ViewModelBase : INotifyPropertyChanged
7{
8 public event PropertyChangedEventHandler? PropertyChanged;
9
10 protected virtual void OnPropertyChanged( PropertyChangedEventArgs args )
11 {
12 this.PropertyChanged?.Invoke( this, args );
13 }
14
15 // Fixed: the base class defines an OnPropertyChanged(string) method.
16 protected void OnPropertyChanged( string propertyName )
17 {
18 this.OnPropertyChanged( new PropertyChangedEventArgs( propertyName ) );
19 }
20}
21
22[Observable]
23public partial class CustomerViewModel : ViewModelBase
24{
25 public string? Name { get; set; }
26}
27
1using Metalama.Patterns.Observability;
2using System.ComponentModel;
3
4namespace Doc.LAMA5156.Fixed;
5
6public abstract class ViewModelBase : INotifyPropertyChanged
7{
8 public event PropertyChangedEventHandler? PropertyChanged;
9
10 protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
11 {
12 this.PropertyChanged?.Invoke(this, args);
13 }
14
15 // Fixed: the base class defines an OnPropertyChanged(string) method.
16 protected void OnPropertyChanged(string propertyName)
17 {
18 this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
19 }
20}
21
22[Observable]
23public partial class CustomerViewModel : ViewModelBase
24{
25 private string? _name;
26
27 public string? Name
28 {
29 get
30 {
31 return _name;
32 }
33
34 set
35 {
36 if (!object.ReferenceEquals(value, _name))
37 {
38 _name = value;
39 OnPropertyChanged("Name");
40 }
41 }
42 }
43
44 protected override void OnPropertyChanged(PropertyChangedEventArgs args)
45 {
46 base.OnPropertyChanged(args);
47 }
48}
49