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
3.07k stars 299 forks source link

NewPropertyChangedEvent on ObservableObject #801

Open Hakoyu opened 12 months ago

Hakoyu commented 12 months ago

Overview

I want to get the old value and the new value in the event

API breakdown

namespace CommunityToolkit.Mvvm.ComponentModel;
public abstract class ObservableObject
{
    protected bool SetProperty<T>(
        [NotNullIfNotNull(nameof(newValue))] ref T field,
        T newValue,
        [CallerMemberName] string? propertyName = null
    )
    {
        if (EqualityComparer<T>.Default.Equals(field, newValue))
        {
            return false;
        }

        OnPropertyChanging(propertyName);

        var oldValue = field;
        if (AnotherPropertyChanging is not null)
            AnotherPropertyChanging?.Invoke(this, new(propertyName, oldValue, newValue));

        field = newValue;

        OnPropertyChanged(propertyName);

        if (AnotherPropertyChanged is not null)
            AnotherPropertyChanged?.Invoke(this, new(propertyName, oldValue, newValue));

        return true;
    }

    public event AnotherPropertyChangingEventHandler? AnotherPropertyChanging;
    public event AnotherPropertyChangedEventHandler? AnotherPropertyChanged;
}

public delegate void AnotherPropertyChangingEventHandler(
    object sender,
    AnotherPropertyChangingEventArgs e
);
public delegate void AnotherPropertyChangedEventHandler(
    object sender,
    AnotherPropertyChangedEventArgs e
);

public class AnotherPropertyChangingEventArgs : PropertyChangingEventArgs
{
    public object? OldValue { get; }

    public object? NewValue { get; }

    public AnotherPropertyChangingEventArgs(
        string? propertyName,
        object? oldValue,
        object? newValue
    )
        : base(propertyName)
    {
        OldValue = oldValue;
        NewValue = newValue;
    }
}

public class AnotherPropertyChangedEventArgs : PropertyChangedEventArgs
{
    public object? OldValue { get; }

    public object? NewValue { get; }

    public AnotherPropertyChangedEventArgs(string? propertyName, object? oldValue, object? newValue)
        : base(propertyName)
    {
        OldValue = oldValue;
        NewValue = newValue;
    }
}

Usage example

public partial class MainWindowViewModel : ObservableObject
{
    AnotherViewModel anotherViewModel = new();

    [ObservableProperty]
    private int _oldValue = 0;

    [ObservableProperty]
    private int _newValue = 0;

    public MainWindowViewModel()
    {
        anotherViewModel.AnotherPropertyChanged += (s, e) =>
        {
            if (e.PropertyName == nameof(AnotherViewModel .Value))
            {
                OldValue = e.OldValue;
                NewValue = e.NewValue;
            }
        };
    }
}

public partial class AnotherViewModel : ObservableObject
{
    [ObservableProperty]
    private int _value = 0;
}

Breaking change?

No

Alternatives

Currently I'm using reflection to get the old value, but that's a very bad.

protected override void OnPropertyChanging(PropertyChangingEventArgs e)
{
    base.OnPropertyChanging(e);
    if (AnotherPropertyChanged is not null)
    {
        _oldValue = this.GetType().GetProperty(propertyName).GetValue(this);
    }
}

Additional context

No response

Help us help you

Yes, I'd like to be assigned to work on this item