如何使用 MvvmCross 为 Seekbar 设置 Start/StopTrackingTouch 的绑定

How to set bindings for Start/StopTrackingTouch for Seekbar using MvvmCross

我得到了一种典型的音乐播放器 window,音乐播放时搜索栏点在移动。

我已经使用默认 mvvmcross 绑定到 属性(通过 EventHandler 绑定更改),如下所示:

 <SeekBar
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:id="@+id/playprogress"
      local:MvxBind="Progress ValueOfTimer"
        />

所以现在我希望用户能够前后移动它。

我一直在尝试这样绑定它:

 public class PlayWindowView : MvxActivity
    {

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            var set = this.CreateBindingSet<PlayWindowView, PlayWindowViewModel>();

            SeekBar seek = FindViewById<SeekBar>(Resource.Id.playprogress);

            set.Bind(seek).For("Max").To(viewModel => viewModel.MaxTimerValue);
            set.Bind(seek).For("StopTrackingTouch").To(viewModel => viewModel.PlayProgressChanged);
            set.Apply();
        }

        protected override void OnViewModelSet()
        {
            SetContentView(Resource.Layout.playwindow_view);
        } 
     }

视图模型部分如下所示:

public class PlayWindowViewModel : MvxViewModel<ListMenuItemDto>
{

    private long _valueOfTimer;

    public long ValueOfTimer
    {
        get { return _valueOfTimer; }

        set
        {
            _valueOfTimer = value;
            RaisePropertyChanged(() => ValueOfTimer);
        }
    }

    //...

    public MvxAsyncCommand<long> PlayProgressChanged
    {
        get { return new MvxAsyncCommand<long>(OnPlayProgressChange);}
    }

    private async Task OnPlayProgressChange(long progr)
    {
        await _playingService.SetTime((int) progr).ConfigureAwait(false);
    }
}

但看起来它不起作用。 我的意思是,它甚至没有进入 OnPlayProgressChange。但在视图中出现它进入命令 PlayProgressChanged 一次。

如何将此事件(以及 StartTrackingTouchStopTrackingTouch 等事件)正确绑定到函数?

P.S。 仅供参考,我使用 MvvmCross 5


UPD 28.11.2017

尝试了自定义绑定,甚至 Progress 绑定现在都停止工作了。 所以,xaml 现在看起来像这样:

  <SeekBar
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:id="@+id/playprogress"
      local:MvxBind="Progress ValueOfTimer, OnStopTrackingTouch PlayProgressChanged"
        />

活页夹代码在这里

public class SeekbarStopTrackingTouchEventBinding: MvxAndroidTargetBinding
{
    private readonly SeekBar _seekbar;
    private IMvxAsyncCommand _command;

    public SeekbarStopTrackingTouchEventBinding(SeekBar seekbar) : base(seekbar)
    {
        _seekbar = seekbar;
        _seekbar.StopTrackingTouch += ViewOnStopTrackingTouch;
    }

    private void ViewOnStopTrackingTouch(object sender, SeekBar.StopTrackingTouchEventArgs e)
    {
        if (_command != null)
        {
            _command.Execute(e);
        }
    }

    public override Type TargetType
    {
        get { return typeof (IMvxAsyncCommand); } 
    }

    protected override void SetValueImpl(object target, object value)
    {
        _command = (IMvxAsyncCommand)value;
    }


    protected override void Dispose(bool isDisposing)
    {
        if (isDisposing)
        {
            _seekbar.StopTrackingTouch -= ViewOnStopTrackingTouch;
        }
        base.Dispose(isDisposing);
    }

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

}

在设置中:

 protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
    {
        base.FillTargetFactories(registry);

        registry.RegisterFactory(new MvxCustomBindingFactory<SeekBar>("OnStopTrackingTouch", (seekbar) => new SeekbarStopTrackingTouchEventBinding(seekbar)));
    }

UPD2

更改绑定如下:local:MvxBind="Progress ValueOfTimer; OnStopTrackingTouch PlayProgressChanged"(注意 ; 此处)并且事件现在触发,是的!

但现在的问题是 - 在 binder _command 中即使在 SetValueImpl 被解雇并且 _command = (IMvxAsyncCommand)value; 没问题后仍保持空值,value 指向已设置ViewModel 属性.

怎么会?

UPD3

发现无法将 object 转换为 IMvxAsyncCommand

我通过更改解决了这个问题 IMvxAsyncCommand _commandIMvxAsyncCommand<SeekBar.StopTrackingTouchEventArgs> _command;

将在答案中总结所有内容。

但现在我有一个问题 - 在这种情况下最好的做法是什么?

所以,我不知道这是不是一个好方法,但目前它的工作,我很高兴。

希望这对像我这样的人有所帮助。

自定义绑定 方法是这里的关键。真正有用的东西在这里:

In MvvmCross how do I do custom bind properties

MVVMCross Bindings in Android

所以,就我而言,为了让应用程序监听 SeekBar OnStopTrackingTouch 事件,我这样做了:

已创建绑定 class:

public class SeekbarStopTrackingTouchEventBinding: MvxAndroidTargetBinding
    {
        private readonly SeekBar _seekbar;
        private IMvxAsyncCommand<SeekBar.StopTrackingTouchEventArgs> _command;
        private string  testString;

        public SeekbarStopTrackingTouchEventBinding(SeekBar seekbar) : base(seekbar)
        {
            _seekbar = seekbar;
            _seekbar.StopTrackingTouch += ViewOnStopTrackingTouch;
        }

        private void ViewOnStopTrackingTouch(object sender, SeekBar.StopTrackingTouchEventArgs e)
        {
            if (_command != null)
            {
                _command.Execute(e);
            }
        }

        public override Type TargetType
        {
            get { return typeof (IMvxAsyncCommand); } 
        }

        protected override void SetValueImpl(object target, object value)
        {
            try
            {
                _command = (IMvxAsyncCommand<SeekBar.StopTrackingTouchEventArgs>)value;
            }
            catch (Exception e)
            {
                Log.Error("SOME BINDER FAIL\n\t" + e.Message + "\n", "SOME BINDER FAIL\n\t" + e.Message + "\n");
                throw;
            }
        }


        protected override void Dispose(bool isDisposing)
        {
            if (isDisposing)
            {
                _seekbar.StopTrackingTouch -= ViewOnStopTrackingTouch;
            }
            base.Dispose(isDisposing);
        }

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

Setup.cs 中放置此代码:

protected override void FillTargetFactories(IMvxTargetBindingFactoryRegistry registry)
{
    base.FillTargetFactories(registry);

    registry.RegisterFactory(new MvxCustomBindingFactory<SeekBar>("OnStopTrackingTouch", (seekbar) => new SeekbarStopTrackingTouchEventBinding(seekbar)));
}

在我的 ViewModel 和命令执行函数中准备 属性:

    public IMvxAsyncCommand<SeekBar.StopTrackingTouchEventArgs> PlayProgressChanged
    {
        get
        {
            return new MvxAsyncCommand<SeekBar.StopTrackingTouchEventArgs>(OnPlayProgressChange);
        }
    }

    private async Task OnPlayProgressChange(SeekBar.StopTrackingTouchEventArgs e)
    {
        var progr = e.SeekBar.Progress;
        await _playingService.SetTime((int) progr).ConfigureAwait(false);
    }

在视图布局中,在 local:MvxBind 内将我的 ViewModel 命令与 Setup.cs

中的 registry.RegisterFactory 中提供的事件名称相关联
  <SeekBar
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:id="@+id/playprogress"
      local:MvxBind="Progress ValueOfTimer; OnStopTrackingTouch PlayProgressChanged"
        />