简体   繁体   中英

Issue in Binding BEMCheckBox to ViewModel - MvvmCross, Xamarin.iOS

I am new to MvvmCross and still figuring out how things are done. I am using BEMCheckBox for one of my developing applications and I tried to bind BEMCheckBox's "On" property to ViewModel. Unfortunately, it is not working as expected.

BEMCheckBox
Github: https://github.com/saturdaymp/XPlugins.iOS.BEMCheckBox
NuGet: SaturdayMP.XPlugins.iOS.BEMCheckBox
Version: 1.4.3

MvvmCross
Version: 6.4.2

This is my View Class

[MvxFromStoryboard("Main")]
[MvxRootPresentation(WrapInNavigationController = false)]
public partial class MyView : BaseView<MyViewModel>
{
    private BEMCheckBox CheckBox;

    public MyView(IntPtr handle) : base(handle)
    {
    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();

        //add check box
        CheckBox = new BEMCheckBox(new CoreGraphics.CGRect(0, 0, 20, 20))
        {
            BoxType = BEMBoxType.Square,
            TintColor = UIColor.FromRGBA(0, 0, 0, 0.14f),
            OnFillColor = UIColor.FromRGB(42, 183, 202),
            OnCheckColor = UIColor.White,
            OnTintColor = UIColor.FromRGBA(0, 0, 0, 0.14f),
            OnAnimationType = BEMAnimationType.Bounce,
            OffAnimationType = BEMAnimationType.Bounce,
            On = false,
            CornerRadius = 0,
        };

        //CheckBoxContainerView is an UIView 
        CheckBoxContainerView.AddSubview(CheckBox);
        CheckBoxContainerView.BackgroundColor = UIColor.Clear;

        //Binding to View Model
        var set = this.CreateBindingSet<MyView, MyViewModel>();
        set.Bind(CheckBox).For(c => c.On).To(vm => vm.IsCheckBoxOn);
        set.Apply();
    }
}

This is my ViewModel Class

public class MyViewModel : BaseViewModel
{
    private bool _isCheckBoxOn;
    public bool IsCheckBoxOn
    {
        get => _isCheckBoxOn;
        set
        {
            SetProperty(ref _isCheckBoxOn, value);
            Console.WriteLine(_isCheckBoxOn);
        }
    }

    public MyViewModel : base()
    {
    }

    public override Task Initialize()
    {
        return base.Initialize();
    }
}

When I do the same thing for UISwitch it works perfectly. Any help would be highly appreciated.

MvvmCross includes many target bindings out of the box, UISwitch being one of them. For a complete list see " built-in-bindings " in MvvmCross documentation.

One-way binding (ViewModel -> View)

By default, you can create a binding to assign a value to a property on your view from your view model, this is called one-way binding. The approach works even with custom 3rd party controls, as long as the types match.

Two-way binding ( ViewModel -> View && View -> ViewModel )

In order to do a two-way bind, MvvmCross needs a mechanise for the view to notify the view model that a value of the view has changed. For this MvvmCross using target bindings. See MvvCross documentation for creating custom target bindings.


Example

See MvvmCross source code for MvxUISwitchOnTargetBinding.cs which shows how they do the binding for the UISwitch control and the On state.

public class MvxUISwitchOnTargetBinding : MvxTargetBinding<UISwitch, bool>
{
    private IDisposable _subscription;

    public MvxUISwitchOnTargetBinding(UISwitch target)
        : base(target)
    {
    }

    protected override void SetValue(bool value)
    {
        Target.SetState(value, true);
    }

    public override void SubscribeToEvents()
    {
        var uiSwitch = Target;
        if (uiSwitch == null)
        {
            MvxBindingLog.Error( "Error - Switch is null in MvxUISwitchOnTargetBinding");
            return;
        }
        _subscription = uiSwitch.WeakSubscribe(nameof(uiSwitch.ValueChanged), HandleValueChanged);
    }

    public override MvxBindingMode DefaultMode => MvxBindingMode.TwoWay;

    protected override void Dispose(bool isDisposing)
    {
        base.Dispose(isDisposing);
        if (!isDisposing) return;
        _subscription?.Dispose();
        _subscription = null;
    }

    private void HandleValueChanged(object sender, EventArgs e)
    {
        FireValueChanged(Target.On);
    }
}

Note the HandleValueChanged method which calls the FireValueChanged() method, this is the method that passes the value that you want to send back up to your bound view model.

You will then need to register your custom target bindings in your Setup.cs class by overriding the FillTargetFactories .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM