'Using INotifyPropertyChanged view models with Cocoa/AppKit bindings

I know this is pretty esoteric but hoping someone has a solution for me.

I have an application that started life as WPF, moved to UWP and now lives primarily as XF/MAUI and WinUI.

I'm wanting to port this to macOS and essentially just replace the UI and retain the MVVM architecture underneath and write as little glue as possible. I'm using Xamarin Mac and C# to do this.

Cocoa supports bindings but the implementation is incompatible with the standard Microsoft MVVM pattern.

My work around at present is to do something like this:

public class LoginModel: NSObject
{
    private LoginViewModel _wrappedVm; // Implements both INotifyPropertyChanged and INotifyPropertyChanging

    /* Reimplement properties on LoginViewModel here and forward to the underlying view model */

    public LoginModel()
    {
        // snip: create the view model
        _wrappedVm.PropertyChanged += (s, e) =>
        {
           DidChangeValue(e.PropertyName);
        }

        _wrappedVm.PropertyChanging += (s, e) =>
        {
           WillChangeValue(e.PropertyName);
        }
    }
}

There is obviously a lot of boilerplate here but it works. I'd love for there to be a way to bind directly to the MVVM view model without an intermediate step, and as a compromise would use a proxy. I haven't investigated proxying it, but given my understanding that the model needs to be an NSObject there might be challenges in doing this.



Solution 1:[1]

Not a big change, but should reduce the boilerplate assumption here is that the DidChangeValue and the WillChangeValue have to be implemented in the ViewModel anyway

public interface INSObjectBindableView
{
   void DidChangeValue(string propertyName);
   void WillChangeValue(string propertyName);
}

public static class NSObjectBindableEx
{
   public static void Bind(this INSObjectBindableView view, NSObject model)
   {
        view.PropertyChanged += (s, e) =>
        {
           DidChangeValue(e.PropertyName);
        }

        view.PropertyChanging += (s, e) =>
        {
           WillChangeValue(e.PropertyName);
        }
   }
}


this allows you to keep the binding code to a single line inside the NSObject sub-class like


public class LoginModel: NSObject
{
    private LoginViewModel _wrappedVm; 

    public LoginModel()
    {
      _wrappedVm.Bind(this);
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Surya Pratap