Handling observable object properties with CommunityToolkit.Mvvm
Asked Answered
M

1

9

How do we handle properties that are objects themselves using CommunityToolkit.Mvvm?

I understand that I can simply use [ObservableProperty] attribute with simple properties e.g. data type of string, int, etc.

How do we handle properties that are POCO objects and need to be observable?

Here's an example:

public partial class MyViewModel : ObservableObject
{
   [ObservableProperty]
   string title;

   [ObservableProperty]
   decimal price;

   Person author; // How do we handle this property that is a Person object?
}

I understand that source generators in CommunityToolkit.Mvvm will automatically handle creation of Title and Price public properties. What about author?

Do we use [ObservableProperty] attribute to make complex properties observable, such as the author property in the above example which is a Person object?

Murky answered 8/6, 2022 at 20:50 Comment(0)
E
19

Here are multiple scenarios:

The entire Person object gets replaced

If you only ever replace the entire Person object and don't change its individual properties (you might select a different person from a list) all you need is to decorate the author field with the ObservablePropertyAttribute.

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public partial class MyViewModel : ObservableObject
{
   [ObservableProperty]
   string title;

   [ObservableProperty]
   decimal price;

   [ObservableProperty]
   Person author;
}

This change will be reflected in the UI:

Author = anotherPerson;

and this one will NOT:

Author.FirstName = "James";

Individial Person properties get changed

If you plan to change the persons individial properties, but keep the instance the same, you need to decorate the individual properties of the Person object with the ObservablePropertyAttribute.

public class Person : ObservableObject
{
    [ObservableProperty]
    string firstName;

    [ObservableProperty]
    string lastName;
}

public partial class MyViewModel : ObservableObject
{
   [ObservableProperty]
   string title;

   [ObservableProperty]
   decimal price;

   public Person Author { get; } = new Person();
}

This change will be reflected in the UI:

Author.FirstName = "James";

and this one will NOT:

Author = anotherPerson;

Or both

Or do both and get the UI to reflect any changes, be it changing an individual property or the entire object instance.

public class Person : ObservableObject
{
    [ObservableProperty]
    string firstName;

    [ObservableProperty]
    string lastName;
}

public partial class MyViewModel : ObservableObject
{  
   [ObservableProperty]
   string title;

   [ObservableProperty]
   decimal price;

   [ObservableProperty]
   Person author;
}

Any of these changes will be reflected in the UI:

Author = anotherPerson;
Author.FirstName = "James";
Electrodeposit answered 14/6, 2022 at 5:10 Comment(2)
While I understand this flow pattern for MVVM, I have Person as a Class in my Models folder, meaning it is not associated to MyViewModel. With that said, how would I apply something like [NotifyCanExecuteChangedFor(nameof(MyCommand))] in the Person class to react/update in MyViewModel as Person doesn't get OnPersonChanged() call, only a child property?Parity
My workaround was adding a TextChanged for each of my properties (entry), Converter from Event to Command (toolkit), then call CanExecuteChanged for the Command in question. Not ideal but this use case is only two properties right now.Parity

© 2022 - 2024 — McMap. All rights reserved.