I just simply want to use a [ObservableProperty]
for corresponding fields/properties.
However, as I am using MvvmCross (what's not so important), my ViewModel already inherited from a base class which does implement INotifyPropertyChanged
itself.
So, when using this, I am getting error:
//[INotifyPropertyChanged]
public partial class MyVewModel : MvxViewModel
{
[ObservableProperty] private string name;
}
MVVMTK0019: Fields annotated with [ObservableProperty] must be contained in a type that inherits from ObservableObject or that is annotated with [ObservableObject] or [INotifyPropertyChanged] (including base types).
But I can't annotate my class with any of those as if I do I get another error:
MVVMTK0001: Cannot apply [INotifyPropertyChanged] to a type that already declares the INotifyPropertyChanged interface.
The whole situation looks kinda ridiculous. Does that mean that I can't use third-party classes that way then? What's the simplicity of CommunityToolkit.Mvvm in in that case?..
You cannot and it doesn't make any sense to do it. Either use MvvmCross or CommunityToolkit.Mvvm, don't mix them within the same class.
You can only use one implementation of
INotifyPropertyChanged
, because there are conventions that the source generators from the MVVM Community Toolkit use which are not satisfied by other implementations. That's why the source generators rely on the implementation of theObservableObject
base class.For example, the
[ObservableProperty]
source generator will generate a property setter that calls the base class'sOnPropertyChanged()
method. Since this method is not part of the interface, other implementations sometimes name it differently, e.g.RaisePropertyChanged()
orNotifyPropertyChanged()
, etc. and even implement it slightly differently, or not at all.Therefore, the resulting auto-generated code wouldn't necessarily compile, because the expected
OnPropertyChanged()
method with the right signature may not exist. Hence, the errors you see. They ensure that the generator can deal with your code and generate the correct, additional parts of the partial class that are used to notify subscribers of changes to the generated properties.Let's assume there are two different implementations of
IPropertyChanged
, let's call themObservableObject
andNotifyObject
:The
[ObservableProperty]
code generator will always generate a property (in another partial class of the same name) similar to the following for a simple backing field that is decorated with it:This is by convention, that's just how the code generator works. It expects the base class to provide the
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
method.The
ObservableObject
implementation satisfies this requirement, theNotifyObject
one doesn't, because the name and signature don't match. The source generator has no straightforward and surefire way to determine whether the correct method exists in the base class that is used unless it checks that a specific one is used.Therefore, this works:
While this doesn't:
In order to avoid issues, the code generator only works with partial classes that inherit from the toolkit's implementation of
ObservableObject
either via the[ObservableObject]
or[INotifyPropertyChanged]
attributes or by directly inheriting from it, which essentially results in the same thing.This may become more clear from a blog post I wrote about this about year ago, specifically the Under the hood section.