2017-11-02 13 views
0

である私は、多分私はここで何かをMvvmCrossとXamarinに新しい欠場していますが、私はそれがここで説明しているようViewViewModelからいくつかのデータを渡そうとしたときに(ほぼ)MvvmCross - ビューモデルmvxInteractionは常にnull

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

しかし、私がそこに通っても、の変数Viewの変数は常にnullです!

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

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

のViewModelコード:

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 2017年9月11日

最後に、それは私が望んでいたように動作します。

代わりのnmilcoffとしてMvxInteraction I単に利用されるサービス、(ところで答えのための多くのおかげで)助言、そして私はそれからトーストを呼び出したときにrunOnUiThreadでそれをラップします。

最終的なコードはここにあります。

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

MenuViewModel:それはMvxInteractionを使用するよう

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

    } 

答えて

1

あなたは、StarWarsSampleは面白いかもしれません。

このアプリでわかるように、後でビューコードでバインディングを宣言する必要があります。 Fluent Bindingブロックをアクティビティの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)トーストを表示する方法とコアレベルのインターフェースを作成します。

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コンテナに登録します。このようなもの(プラットフォームプロジェクトのセットアップクラス内):

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

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

これはそれです。あなたはどこでもあなたのIToastServiceを注入/解決する準備が整いました!

+0

ああ、試してみよう! – DanilGholtsman

+0

ああ、今はnullではありませんが、OnIteractionRequestedはトグルされていません。 – DanilGholtsman

+0

OnInteractionRequested内にブレークポイントを設定した場合、ヒットしませんか?それ以外の場合は、デバッガがメソッドにステップインしている場合は、電話のキーボードが表示されていないことを確認します。 – nmilcoff