Wednesday, February 4, 2015

iOS UISegmentedControl custom binding in MVVMCross

Working on a UI screen for an MVVM view using the UISegmented Control.  My view needed to handle the SelectedSegment event which is not part of the MVVMCross libraries.  The good news is that MVVMCross Framework is extensible.  Stuart Lodge did 2 of his N+1 series on this particular subject.  There was some confusion on my part about how exactly to do this until I hit on this stackoverflow post.  The author provided the target binding for the Segmented control with enough hints to get me to the working solution.

Solution:
Create the file MvxUISegmentedControlSelectedSegmentTargetBinding.cs and place it in the Touch project:

1.)MvxUISegmentedControlSelectedSegmentTargetBinding .cs

public class MvxUISegmentedControlSelectedSegmentTargetBinding : MvxPropertyInfoTargetBinding<UISegmentedControl>
{
    public MvxUISegmentedControlSelectedSegmentTargetBinding(object target, PropertyInfo targetPropertyInfo)
        : base(target, targetPropertyInfo)
    {
        this.View.ValueChanged += HandleValueChanged;
    }

    private void HandleValueChanged(object sender, System.EventArgs e)
    {
        var view = this.View;
        if (view == null)
        {
            return;
        }
        FireValueChanged(view.SelectedSegment);
    }

    public override MvxBindingMode DefaultMode
    {
        get { return MvxBindingMode.TwoWay; }
    }

    protected override void Dispose(bool isDisposing)
    {
        base.Dispose(isDisposing);
        if (isDisposing)
        {
            var view = this.View;
            if (view != null)
            {
                view.ValueChanged -= HandleValueChanged;
            }
        }
    }
}

2.)Touch project Setup.cs file needs to register the target factories

protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
        registry.RegisterPropertyInfoBindingFactory(typeof(MvxUISegmentedControlSelectedSegmentTargetBinding), typeof(UISegmentedControl), "SelectedSegment");
}
The key here is that the 3rd argument must be match the SelectedSegment property in the UISegmentedControl.

3.)Core project ViewModel needs to include an integer property to bind against the SelectedSegment property. 

ViewModel

private int _selectedSegment

public int SelectedSegment
{
get {return _selectedSegment;}
set
{
   _selectedSegment = value;
   RaisePropertyChanged(); => SelectedSegment;
}


4.)  Touch project View needs to bind the SelectedSegment in the ViewModel to the SelectedSegment in the Mvx control

View Model

public override void ViewDidLoad()
{
....
var segmentControl = new UISegmentedControl();
....
var set = this.CreateBindingSet<View,ViewModel>();

set.Bind(segmentControl).For(sm=>sm.SelectedSegment).To(vm=>vm.SelectedSegment);
...


Source:

1.)mvvmcross-and-uibutton-selected-uisegmentedcontrol-bindings-ios
2.)Stuart Lodge's github repo
3.)MVVMCross N+1 N28 (Custom Binding)
4.)MVVMCross N+1 N19 (Custom Control)
5.)