0

I'm having an issue have a property shared between two derived ViewModels:

public abstract class MyBaseViewModel : ViewModelBase
{
    private string _sharedProperty;
    public string SharedProperty
    {
        get => _sharedProperty;
        set => this.RaiseAndSetIfChanged(ref _sharedProperty, value);
    }
}

public abstract class ViewModelA : MyBaseViewModel
{

}

public abstract class ViewModelB : MyBaseViewModel
{

}

public sealed partial class FirstPage : IViewFor<ViewModelA>
{
    this.Bind(ViewModel,
        vm => vm.SharedProperty,
        view => view.MycontrolA.Text)
    .DisposeWith(disposable);
}

public sealed partial class SecondPage : IViewFor<ViewModelB>
{
    this.Bind(ViewModel,
        vm => vm.SharedProperty,
        view => view.MycontrolB.Text)
    .DisposeWith(disposable);
}

When I update SharedProperty from SecondPage, the binding on FirstPage is not updated. Now obviously each ViewModel has its own instance of that property since it's not static. Since RaiseAndSetIfChanged needs an instance to execute, how can we have a property that is bound in two different views and share its binding??

Maximus
  • 1,441
  • 14
  • 38

1 Answers1

2

Consider using DependencyInjection and some sort of registered constant value to store the registration between the two objects. Then use a ObservableAsPropertyHelper to keep your properties up to date.

Register your in your Splat DI

    private static void RegisterDynamic(IMutableDependencyResolver resolver)
    {
         resolver.RegisterConstant<IMyDataType>(new MyDataType());
    }

Then in your ViewModels constructors you can do

public class ViewModelA : IDisposable
{    
    private readonly ObservableAsPropertyHelper<string> sharedProperty;
    private readonly IMyDataType dataType;

    public ViewModelA(IMyDataType dataType = null)
    {
        this.dataType = dataType ?? Locator.Current.GetService<IMyDataType>();
        this.sharedProperty = dataType.WhenAnyValue(x => x.SharedProperty).ToProperty(this, x => x.SharedProperty);
    }

    public string SharedProperty => this.sharedProperty.Value;

    public void Dispose() => this.sharedProperty?.Dispose();
}

Then you can repeat the same process for ViewModelB.

One additional consideration you'll need to consider, is you'll likely want to dispose of the Subscription for ToProperty(). In the example above I've just done a simple Dispose, there are also mechanisms for WhenActivate you can use.

Glenn Watson
  • 2,758
  • 1
  • 20
  • 30
  • The reason why I use the nullable type for passing in dataType, is for easier testing if you want to run your unit tests with a different data store. – Glenn Watson Jul 27 '18 at 18:45
  • Great answer! I never thought of using Splat in that sense. Thanks. – Maximus Jul 27 '18 at 18:54