tom-pratt
tom-pratt

Reputation: 382

MvvmCross binding + Android EventHandler

I have a situation in MvvmCross Android where I have a SeekBar's position bound to a property in the view model. The property can be updated by sliding the seek bar or by an external api interaction taking place over web sockets. If the user is currently sliding the seek bar, I don't want the external api to be able to update the property and cause the seek bar to visibly jump around.

I'm trying to do this by setting an IsDimming property when the user starts sliding and stops sliding. However as soon as I assign these native EventHandlers, the set {} part of my property is no longer hit when you drag the seek bar.

Binding in the XML view:

<SeekBar
    android:layout_width="120dp"
    android:layout_height="wrap_content"
    android:layout_gravity="center_vertical"
    android:id="@+id/seekBar"
    android:max="100"
    local:MvxBind="Progress DimmerPosition" />

Properties in the view model:

public bool IsDimming { get; set; }

private float _dimmerPosition;
public float DimmerPosition {
    get {
        return _dimmerPosition;
    }
    set { // This isn't hit when I have assigned native event handlers
        _dimmerPosition = value;
        _eventService.SendLightingState (UUIDAction, Number, value);
        RaisePropertyChanged (() => DimmerPosition);
    }
}

My native Android event handlers in the view's code behind:

var slider = FindViewById<SeekBar> (Resource.Id.seekBar);
slider.StartTrackingTouch += (object sender, SeekBar.StartTrackingTouchEventArgs e) => {
    ViewModel.IsDimming = true;
};

slider.StopTrackingTouch += (object sender, SeekBar.StopTrackingTouchEventArgs e) => {
    ViewModel.IsDimming = false;
};

Is there any way I can have the binding AND use the event handlers? Worth noting that the binding continues to work ok in iOS when I assign to the TouchDown and TouchUpInside event handlers.

Many thanks

Tom

Upvotes: 2

Views: 1101

Answers (1)

Stuart
Stuart

Reputation: 66882

I suspect this is caused by both the MvvmCross binding and the internal Xamarin event handling both using SeekbarListener's - while Java only allows one of them to work at a time.

In MvvmCross's case, this listener is at https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Droid/Target/MvxSeekBarProgressTargetBinging.cs#L41

One way around this for your case is: you could replace MvvmCross's binding with a custom binding which uses a ProgressChanged event handler instead of a listener. To do this:

  1. Copy the code from https://github.com/MvvmCross/MvvmCross/blob/3.5/Cirrious/Cirrious.MvvmCross.Binding.Droid/Target/MvxSeekBarProgressTargetBinging.cs into your own project and then rename it to MySeekBarProgressTargetBinding
  2. Change the SubscribeToEvents code to use an event delegate subscription instead of the listener. Also, be sure to unsubscribe in Dispose too.
  3. Change your Setup code to register MySeekBarProgressTargetBinding for "Progress" (as long as you do this after the core Mvx one, then I think your one will "win")

    registry.RegisterPropertyInfoBindingFactory(typeof(MySeekBarProgressTargetBinding), typeof(SeekBar),
                                                "Progress");
    

I think that should work....

Extra bonus points are also available if you push some changes back to Mvx that address this for everyone (and that fix the name from Binging to Binding too). I believe that when that bit of Mvx was written, then the event handlers either weren't available or weren't working (that's why it used a custom listener).

Upvotes: 2

Related Questions