CommunityToolkit / dotnet

.NET Community Toolkit is a collection of helpers and APIs that work for all .NET developers and are agnostic of any specific UI platform. The toolkit is maintained and published by Microsoft, and part of the .NET Foundation.
https://docs.microsoft.com/dotnet/communitytoolkit/?WT.mc_id=dotnet-0000-bramin
Other
2.99k stars 294 forks source link

Set PropertyChanged methods protected #836

Closed Pantheas closed 5 months ago

Pantheas commented 8 months ago

Overview

It would be nice if the following methods could get a protected modifier instead of private so these methods can be accessed from derived classes aswell. I have scenarios in which I define common properties tagged with [ObservableProperty] in a base class. However, if I want to react on changes from a derived class I currently have to implement a wrapping method just to modify the accessibility.

partial void On[PropertyName]Changing(global::[PropertyType] value);
partial void On[PropertyName]Changing(global::[PropertyType] oldValue, global::[PropertyType] newValue);
partial void On[PropertyName]Changed(global::[PropertyType] value);
partial void On[PropertyName]Changed(global::[PropertyType] oldValue, global::[PropertyType] newValue)

API breakdown

protected partial void On[PropertyName]Changing(global::[PropertyType] value);
protected partial void On[PropertyName]Changing(global::[PropertyType] oldValue, global::[PropertyType] newValue);
protected partial void On[PropertyName]Changed(global::[PropertyType] value);
protected partial void On[PropertyName]Changed(global::[PropertyType] oldValue, global::[PropertyType] newValue);

Usage example

public partial abstract class ViewModelBase :
    ObservableObject
{
    [ObservableProperty]
    private bool isInitialized = false;
}

public partial class SomeDerivedViewModel :
    ViewModelBase
{
    protected partial void OnIsInitializedChanged(
        bool value)
    {
        // do something that should happen when this property value changed...
    }
}

Breaking change?

No

Alternatives

public partial abstract class ViewModelBase :
    ObservableObject
{
    [ObservableProperty]
    private bool isInitialized = false;

    partial void OnIsInitializedChanged(
        bool value)
    {
        HandleIsInitializedChanged(
            value);
    }

    protected virtual void HandleIsInitializedChanged(
        bool value)
    {
    }

}

public partial class SomeDerivedViewModel :
    ViewModelBase
{
    protected override void HandleIsInitializedChanged(
        bool value)
    {
        // do something that should happen when this property value changed...
    }
}

Additional context

Help us help you

Yes, but only if others can assist I have never worked with source generators so far. However, I'm interesting in it and I am up to contribute a solution with some assistance.

weitzhandler commented 5 months ago

I find this to be very compelling. Please enable customization of the ObservableProperty, by adding some properties to it, to control accessibility modifiers of its methods, as well as making it virtual, to enable inheriting classes to override and intercept the changing/ed calls.

Sergio0694 commented 5 months ago

This is not doable, as adding an accessibility modifier to a partial method without implementation makes it required to implement it. Right now, the point is that you only implement the ones you need (which is also why there's multiple overloads that are generated). If we added protected, you'd be forced to always implement all those 4 methods for each single property you have, even if you don't actually need them at all.