dotnet icon indicating copy to clipboard operation
dotnet copied to clipboard

Enable other classes that already implement the `INotifyPropertyChanged` to leverage Source Generator Attributes

Open hawkerm opened this issue 2 years ago • 2 comments

Overview

For instance, I already have a class I'm using which inherits from INotifyPropertyChanged. In my scenario, it's ObservableCollection, so I can't modify it as it's in the BCL.

public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged

It already has an OnPropertyChanged helper and PropertyChanged event:

        protected virtual event PropertyChangedEventHandler? PropertyChanged;

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChanged?.Invoke(this, e);
        }

It would be great if I could still use some or all of the MVVM attributes for source generators like [ObservableProperty] when inheriting from these classes in my own class.

API breakdown

N/A uses existing attributes.

Usage example

For instance, I have a class already inheriting from this:

public partial class MyClass : ObservableCollection<T>
{
     // Since my parent class already inherits from INotifyPropertyChanged (and already has a OnPropertyChanged method), just use those...
     [ObservableProperty]
     private bool _isModified;
}

Worst case, let me have to re-specify that I want whatever's needed to polyfill, either with INotifyPropertyChanged or ObservableObject:

[INotifyPropertyChanged]
public partial class MyClass : ObservableCollection<T>
{
     [ObservableProperty]
     private bool _isModified;

     partial OnIsModifiedChanged(bool value)
     {
         // Yay, I could also do this now...
     }
}

Basically the existing generator in this case would spit out all the same stuff except what's already implemented by the type (in the case of ObservableCollection it'd be the following:

    partial class MyClass : global::System.ComponentModel.INotifyPropertyChanged
    {
        //// The Event and the event args OnPropertyChanged are already implemented, so skip adding them

        /// <summary>
        /// Raises the <see cref = "PropertyChanged"/> event.
        /// </summary>
        /// <param name = "propertyName">(optional) The name of the property that changed.</param>
        [global::System.CodeDom.Compiler.GeneratedCode("CommunityToolkit.Mvvm.SourceGenerators.INotifyPropertyChangedGenerator", "8.1.0.0")]
        [global::System.Diagnostics.DebuggerNonUserCode]
        [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
        protected void OnPropertyChanged([global::System.Runtime.CompilerServices.CallerMemberName] string? propertyName = null)
        {
            OnPropertyChanged(new global::System.ComponentModel.PropertyChangedEventArgs(propertyName));
        }

        //// All the SetProperty helpers, TaskNotifier, etc...

If there's any conflict for some particular type, then raise an analytic warning/error.

Breaking change?

No

Alternatives

Can't use MVVM Toolkit generators or helpers? 😥

Additional context

Don't know if I know enough to help here. Had a hard time trying to understand how the existing code was generated with the new fanciness...

Help us help you

Yes, if someone can help (I'm not sure I understand where the current INotifyPropertyChanged generator is and how it works. Nor do I know if I know how to detect if something inherits or has the required methods to skip outputting them... but beyond that, I'd be willing to assist giving it a go if pointed in the right directions.

hawkerm avatar Feb 23 '23 08:02 hawkerm

It would be nice for integrating with Caliburn.Micro base classes for screens and conductors.

eeevans avatar Apr 18 '23 01:04 eeevans

I have a similar use case for writing custom controls in Maui, they inherit already from 'ContentView' which implements INotifyPropertyChanged. Have some properties that I would like to add an ObservableProperty attribute to but it's not currently possible.

varyamereon avatar Sep 15 '23 21:09 varyamereon