MvvmCross - 视图模型 mvxInteraction 始终为空 [英] MvvmCross - View Model mvxInteraction is always null

查看:31
本文介绍了MvvmCross - 视图模型 mvxInteraction 始终为空的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 MvvmCross 和 Xamarin 的新手,也许我在这里错过了一些东西,但是当我尝试将一些数据从 ViewModel 传递到 View 时,就像这里描述的那样(几乎)

I am new to MvvmCross and Xamarin, maybe I miss something here but when I trying to pass some data from ViewModel to View like it's described here (almost)

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

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

But the thing is - my MvxInteraction variable in View is always null, even though I pass there string!

   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();
        }

    }

查看代码:

  [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();
        }


    }

UPD 09.11.2017

最后让它按照我想要的方式工作.

Finally make it work in the way I wanted to.

我只是简单地使用了服务,而不是 MvxInteraction,正如 nmilcoff(顺便说一句,非常感谢您的回答)建议,当我从它调用 toast 时,将它包装在 runOnUiThread 中.

Instead of MvxInteraction I just simply used service, as nmilcoff (thanks much for the answer btw) advised, and when I called toast from it wrap it in runOnUiThread.

所以,最终代码在这里.

So, final code is here.

ToastService:

ToastService:

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()
            );
        }
    }

菜单视图模型:

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

        public MenuViewModel(IDataScanner dataScanner, IToastService toastService)
        {
            _dataScanner = dataScanner;
            _toastService = toastService;
        }

        public override void ViewAppeared()
        {
            base.ViewAppeared();
            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);
            //  Someval = files[0];
           _toastService.ShowToast(files[0]);
        }

    }

推荐答案

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

You might find the StarWarsSample interesting, as it uses MvxInteraction.

正如您在该应用程序中看到的,您需要稍后在您的视图代码中声明绑定.你能把 Fluent Binding 块移动到 Activity 的 OnCreate(Android.OS.Bundle bundle) 方法吗?像这样:

As you can see in that app, you need to declare the bindings later in your View code. Can you move the Fluent Binding block to the Activity's OnCreate(Android.OS.Bundle bundle) method? Something like this:

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.因此,我建议您改用依赖服务:

But that probably won't work because you're requesting the MvxInteraction too soon in your code. Therefore I recommend you to use a Dependency Service instead:

1) 使用显示 Toast 的方法在 Core 级别创建一个界面:

1) Create an interface at Core level with a method that displays a toast:

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

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

2) Create an implementation of the service at platform level:

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 容器注册您的服务.像这样(在您的平台项目的 Setup 类中):

3) Register your service with the IoC Container. Something like this (inside the Setup class of your platform project):

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

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

就是这样.您已准备好在任何地方注入/解析您的 IToastService!

That's it. You're ready to inject/resolve your IToastService wherever you want!

这篇关于MvvmCross - 视图模型 mvxInteraction 始终为空的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆