MvvmCross - 视图模型mvxInteraction始终为null

时间:2017-11-02 12:11:16

标签: c# android xamarin.android mvvmcross

我是MvvmCross和Xamarin的新手,也许我在这里想念一些东西,但是当我尝试将一些数据从rownums传递到ViewModel时就像这里所描述的那样(差不多)

https://www.mvvmcross.com/documentation/fundamentals/mvxinteraction

但问题是 - View中的MvxInteraction变量始终为空,即使我传递了字符串!

View

ViewModel代码:

   public IMvxInteraction<MenuViewModel.YesNoQuestion> Interaction
        {
            get
            {
                return _interaction;
            }
            set
            {
                if (_interaction != null) // <-- Always NULL!
                    _interaction.Requested -= OnInteractionRequested;

                _interaction = value;
                _interaction.Requested += OnInteractionRequested;
            }
        }

查看代码:

  public class MenuViewModel : MvxViewModel
    {
        private IDataScanner _dataScanner { get; set; }

        //demo
        public class YesNoQuestion
        {
            public string Question { get; set; }
        }

        private MvxInteraction<YesNoQuestion> _interaction = new MvxInteraction<YesNoQuestion>();
        // need to expose it as a public property for binding (only IMvxInteraction is needed in the view)
        public IMvxInteraction<YesNoQuestion> Interaction
        {
            get
            {
                return _interaction;
            }
        }


        private void DoFinishProfileCommand()
        {
            // 1. do cool stuff with profile data
            // ...

            // 2. request interaction from view
            // 3. execution continues in callbacks
            var request = new YesNoQuestion
            {
                Question = "Do you want to save your profile?"
            };

            _interaction.Raise(request);
        }
        // demo

        public class DataEventArgs : EventArgs
        {
            public List<string> DataList;
        }

        public delegate void ScanDoneEvent(object sender, DataEventArgs args);
        public event ScanDoneEvent ScanDone;

        protected virtual void OnScanDone(List<string> dataList)
        {
            ScanDone?.Invoke(this, new DataEventArgs { DataList = dataList });
        }

        public MenuViewModel(IDataScanner dataScanner)
        {
            _dataScanner = dataScanner;

            RunScan();
        }

        private ObservableCollection<string> _filesCollection;
        public ObservableCollection<string> FilesCollection
        {
            get { return _filesCollection; }
            set
            {
                _filesCollection = value;
                RaisePropertyChanged(() => FilesCollection);
            }
        }

        private async void RunScan()
        {
            var files = await _dataScanner.GetDataListAsync().ConfigureAwait(false);
            FilesCollection = new ObservableCollection<string>(files);
            DoFinishProfileCommand();
        }

    }

UPD 09.11.2017

最后让它以我想要的方式运作。

而不是MvxInteraction我只是简单地使用服务,因为nmilcoff(非常感谢btw的答案)建议,当我从它调用toast时将它包装在 [Activity] public class MenuView : MvxActivity { public MenuView() { var set = this.CreateBindingSet<MenuView, MenuViewModel>(); set.Bind(this).For(view => view.Interaction).To(viewModel => viewModel.Interaction).OneWay(); set.Apply(); } protected override void OnViewModelSet() { SetContentView(Resource.Layout.menu_view); } //demo private IMvxInteraction<MenuViewModel.YesNoQuestion> _interaction; public IMvxInteraction<MenuViewModel.YesNoQuestion> Interaction { get { return _interaction; } set { if (_interaction != null)// <-- Always NULL! _interaction.Requested -= OnInteractionRequested; _interaction = value; _interaction.Requested += OnInteractionRequested; } } private async void OnInteractionRequested(object sender, MvxValueEventArgs<MenuViewModel.YesNoQuestion> eventArgs) { var yesNoQuestion = eventArgs.Value.Question; // show dialog Toast.MakeText(this, yesNoQuestion, ToastLength.Long).Show(); } } 中。

所以,最终的代码在这里。

ToastService:

runOnUiThread

MenuViewModel:

public class ToastService : IToastService
    {
        private readonly IMvxAndroidCurrentTopActivity _topActivity;

        public ToastService(IMvxAndroidCurrentTopActivity topActivity)
        {
            _topActivity = topActivity;
        }

        public void ShowToast(string message)
        {
            _topActivity.Activity.RunOnUiThread(
                () => Toast.MakeText(_topActivity.Activity.ApplicationContext, message, ToastLength.Long).Show()
            );
        }
    }

1 个答案:

答案 0 :(得分:2)

您可能会发现StarWarsSample有趣,因为它使用MvxInteraction

正如您在该应用中所看到的,您需要稍后在View代码中声明绑定。您可以将Fluent Binding块移动到Activity的OnCreate(Android.OS.Bundle bundle)方法吗?像这样:

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

    var set = this.CreateBindingSet<MenuView, MenuViewModel>();
    set.Bind(this).For(view => view.Interaction).To(viewModel => viewModel.Interaction).OneWay();
    set.Apply();
}

但这可能不会起作用,因为您在代码中过早地请求MvxInteraction。因此,我建议您改为使用依赖服务:

1)使用显示toast的方法在Core级别创建一个接口:

public interface IToastService
{
    void ShowToast(string message);
}

2)在平台级别创建服务的实现:

public class ToastService : IToastService
{
    private readonly IMvxAndroidCurrentTopActivity _topActivity;

    public ToastService(IMvxAndroidCurrentTopActivity topActivity)
    {
        _topActivity = topActivity;
    }

    public void ShowToast(string message)
    {
        Toast.MakeText(activity.ApplicationContext, message, ToastLength.Short).Show();
    }
}

3)使用IoC Container注册您的服务。像这样的东西(在你的平台项目的Setup类中):

protected override void InitializeLastChance()
{
        base.InitializeLastChance();

        Mvx.RegisterType<IToastService, ToastService>();
}

那就是它。您已准备好随时随地注入/解决您的IToast服务!