user8470673
user8470673

Reputation:

Mvvmcross Two-way binding between custom properties

I can't understand, how can I bind two custom property between View and ViewMode with Two-Way mode. First I have a same ViewModel like:

//ViewModel
    public class MyViewModel : MvxViewModel
    {
    ....

    private MyMode _testA

    public MyMode TestA
    {
        get => _testA;
        set { 
            _testA = value;
            RaisePropertyChanged(()=> TestA);
            }
    }


        public  MyViewModel()
        {
            TestA = MyMode.A;
        }

            ........
    }

And in View I do bind with my custom property:

//View
 public partial class MyView : MvxViewController<MyViewModel>
 {

    public MyMode UiTestA

     private void SetBiding()
        {
            var set = this.CreateBindingSet<MyView, MyViewModel>();
            set.Bind(this).For(x => x.UiTestA()).To(vm => vm.TestA);
            set.Apply();
        }

    private void SomeMethod()
        {
            var t1 = UiTestA; // t1 = MyMode.A;
            UiTestA = MyMode.B; // Two way binding?
            var t2 = ViewModel.TestA; // MyMode.A; 
        }
 }

If I change TestA in ViewModel, I can get this in View, but I want change it in View and find new value in ViewModel.

Upvotes: 2

Views: 1328

Answers (1)

Cheesebaron
Cheesebaron

Reputation: 24460

Per default MvvmCross can bind any public properties, in OneWay mode. To get TwoWay mode working you need to create at target binding which allows to set from Target to Source. These are called TargetBindings.

Lets say your view has a property called Hello and an event called HelloChanged. With these two in hand you can create a simple TargetBinding:

public class MyViewHelloTargetBinding
    : MvxConvertingTargetBinding
{
    protected MyView View => Target as MyView;

    private bool _subscribed;

    public MyViewHelloTargetBinding(MyView target)
        : base(target)
    {
    }

    private void HandleHelloChanged(object sender, EventArgs e)
    {
        var view = View;
        if (view == null) return;

        FireValueChanged(view.Hello);
    }

    public override MvxBindingMode DefaultMode = MvxBindingMode.TwoWay;

    public override void SubscribeToEvents()
    {
        var target = View;
        if (target == null)
        {
            MvxBindingTrace.Trace(MvxTraceLevel.Error,
                "Error - MyView is null in MyViewHelloTargetBinding");
            return;
        }

        target.HelloChanged += HandleHelloChanged;
        _subscribed = true;
    }

    public override Type TargetType => typeof(string);

    protected override void SetValueImpl(object target, object value)
    {
        var view = (MyView)target;
        if (view == null) return;

        view.Hellp = (string)value;
    }

    protected override void Dispose(bool isDisposing)
    {
        base.Dispose(isDisposing);
        if (isDisposing)
        {
            var target = View;
            if (target != null && _subscribed)
            {
                target.HelloChanged -= HandleHelloChanged;
                _subscribed = false;
            }
        }
    }
}

Then you just need to register your target binding in your Setup.cs file in FillTargetFactories:

registry.RegisterCustomBindingFactory<MyView>(
    "Hello", view => new MyViewHelloTargetBinding(view));

Upvotes: 1

Related Questions