3

In a .NET MAUI application I am using the Mvvm.CommunityToolkit with source generation capabiliities for INotifyPropertyChanged support in my ViewModels:

https://learn.microsoft.com/en-us/dotnet/communitytoolkit/mvvm/generators/observableproperty

Now I am facing a design challenge. Sticking with the example:

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string? firstName;

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string? lastName;


public string FullName => $"{FirstName} {LastName}";

This is all well and good, FullName will get updated when it is bound in the UI, etc.

Now what do I do if I have another property that needs to update whenever FullName gets updated?

Take this (admittedly contrived) example (I want to keep this very simple, the practical application is given at the end):

public int NumberOfXsInName => FullName.Count(x => char.ToLower(x) == 'x');

How can I get that notification? I do not want to add [NotifyPropertyChangedFor] to all properties that notify FullName, since that seems not very resilient, especially since I can not enforce that subclasses will do that correctly.

Do I have to write in the constructor of my ViewModel

PropertyChanged += (_, e) =>
{
    if (e?.PropertyName?.Equals(nameof(FullName)) ?? false)
    {
        OnPropertyChanged(nameof(NumberOfXsInFullName));
    }
};

This seems very verbose for just wanting to "chain up" the PropertyChanged notification through a read-only property (since I can not raise it in a setter)

(*) In practice, I want to split a FilteredCollection, that is based on a DataSource and a FilterFunction, into Groups. Here, the FilteredCollection is just a readonly property that gets notified (like FullName in the example), and I want to split this into two groups based on some criteria for consumption in a different view.

Hottemax
  • 305
  • 1
  • 12
  • have you tried using `[DependsOn]` instead? – Jason Jun 29 '23 at 11:46
  • Can you clarify what you mean, where would I find this annotation? It does not seem to be part of the CommunityToolkit.Mvvm API ? – Hottemax Jun 29 '23 at 13:32
  • 2
    sorry, I assumed it was in CommunityToolkit, we actually get ours from the Fody PropertyChanged nuget – Jason Jun 29 '23 at 13:59

1 Answers1

0

new post #1

I would suggest going back to basics and using something like the following:

public class Class1: ObservableObject
{
    private string lastName;
    private string firstName;
    private string fullName;

    public string FirstName
    {
        get => firstName;
        set
        {
            SetProperty(ref firstName, value);
            UpdateFullName();
        }
    }

    public string LastName
    {
        get => lastName;
        set
        {
            SetProperty(ref lastName, value);
            UpdateFullName();
        }
    }

    private void UpdateFullName()
    {
        FullName = $"{FirstName} {LastName}";
    }

    public string FullName
    {
        get => fullName;
        private set
        {
            if (SetProperty(ref fullName, value))
            {
                OnPropertyChanged(nameof(NumberOfXsInName));
            }
        }
    }

    public int NumberOfXsInName => FullName.Count(x => char.ToLower(x) == 'x');
}

Original post with code that does not work as intended but has been retained due to comment 1 by @HotteMax

As

[ObservableProperty]
[NotifyPropertyChangedFor(nameof(FullName))]
private string? firstName;

expands to

public string? FirstName
{
    get => firstName;
    set
    {
        if (SetProperty(ref firstName, value))
        {
            OnPropertyChanged("FullName");
        }
    }
}

I guess that you could have something like the following (sticking with the tool kit)

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(NotifyFullNameDependents))]
private string? firstName;

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(NotifyFullNameDependents))]
private string? lastName;

[RelayCommand]
private void NotifyFullNameDependents()
{
    OnPropertyChanged(nameof(FullName));
    OnPropertyChanged(nameof(NumberOfXsInName));    
}

public string FullName => $"{FirstName} {LastName}";

public int NumberOfXsInName => FullName.Count(x => char.ToLower(x) == 'x');

but this would leave a public IRelayCommand property.

ChrisBD
  • 9,104
  • 3
  • 22
  • 35
  • Hmm, no, that merely sets the CanExecuteChanged status, it does not "run" the command. Anyway, I dont want a RelayCommand just for propagating around PropertyChanged events ... – Hottemax Jun 29 '23 at 18:13
  • @Hottemax Thank you for checking. I don't think that you can use the Toolkit in the way that you want' I've updated my answer to include a potential work around – ChrisBD Jun 30 '23 at 16:59