0
votes

I've been trying to find the correct approach for this problem I got, using Prism with Xamarin Forms:

I've a model class, Customer, that contains another class, Address as a property. In my view, I show fields from both objects. I would like to have a "save" button, that only gets enabled after you've made some changes to those models.

Now, the button is bound to a Command, with the corresponding CanSave() function, as is normal with DelegateCommands. I'm trying to find an approach where I can end up with a single IsDirty property on my view model, that gets to "true" after any changed to the underlying models.

The MVVM approach

First thing I thought was the "purist" mvvm approach. A "flat" view model, with properties for each visual element, implemented as a Prism BindableObject, where each getter/setter gets/sets values from/to the underlying model classes.

That failed though, since SetProperty<> has a ref parameter, where I can't use properties from my models.

The over-engineered approach [?]

Second thing I thought was that, if my inner models were observables themselves, I could listen for changes from all of them, throughout the tree. Which opens up a whole new world of issues. Do I register property change listeners in my View model ? Do I make inner models observables, and have the parents listen for change events on their children and propagate that ?

Won't that observable models approach quickly become event handler hell ?

The simplest thing

And last, the simplest thing possible. I have a flat observable ViewModel, that only reads/writes values to/from the actual inner hierarchical model upon read & save

What do you guys think ?

2

2 Answers

0
votes

Maybe I didn't understand your question right, but I'm wondering why you limit yourself to such a small helper function like SetProperty. It has 4 Lines of code. All it does is checking for equality, setting a value and raising an event.

You could easily create another helper function like this.

MyBindableBase

protected virtual bool SetProperty<T>(Func<T> get, Action<T> set, T value, [CallerMemberName] string propertyName = null)
{
    if (object.Equals(get(), value)) return false;

    set(value);
    OnPropertyChanged(propertyName);

    return true;
}

Model

class Model
{
    public string Property { get; set; }
}

ViewModel

class ViewModel : BindableBase
{
    private Model Model { get; set; }

    public string Property
    {
        get { return Model.Property; }
        set { SetProperty(() => Model.Property, x => Model.Property = x, value); }
    }
}

I think you can shorten the usage, if you introduce some naming rules for the mapping and/or use reflections.

0
votes

Well, in the end I went for option 3, the simplest thing I could do.

I was leaning towards returning properties from my model, which would be easy, and using the nullable [?.] syntax it would be null-safe too, but I found that at times I'll have to wrap the actual model properties with something that is more UI-friendly, exposing more/different properties than my actual DB model classes.

So, I went for that, until some other complexity forces me to change my mind again :)

Thanks a lot @Sven-Michael Stübe and @adminSoftDK for the help