2017-12-06 16 views
2

ReactiveUI Interactionを使用して2番目のウィンドウをモーダルダイアログとして開き、2番目のウィンドウのListBoxからデータを返すウィンドウがあります。ReactiveUI:カスタムダイアログからの戻り値

問題は、.ShowDialog()が完了すると、ViewModelのSelectedItemは常にnullに評価されることです。バインドが正しく機能していることを確認しました。選択した項目がダイアログウィンドウのViewModelで正しく更新されています。 Interactionに戻り、プロパティがデフォルト値(null)にリセットされたときだけです。

私は一緒にここでの問題の最小限の例を入れている:

https://github.com/replicaJunction/ReactiveDialogTest

テスト中のメインロジックはMainWindowViewModel.csです。

編集:ここでは基本的な考え方を持つコードからの抜粋だ:問題を再現するために

GetNumberFromDialog = new Interaction<Unit, int>(); 
GetNumberFromDialog.RegisterHandler(interaction => 
{ 
    var vm = new DialogWindowViewModel(); 

    // Get a reference to the view for this VM 
    var view = Locator.Current.GetService<IViewFor<DialogWindowViewModel>>(); 

    // Set its VM to our current reference 
    view.ViewModel = vm; 

    var window = view as Window; 
    var dialogResult = window.ShowDialog(); 

    // At this point, vm.SelectedNumber is expected be the number the user selected - 
    // but instead, it always evaluates to 0. 

    if (true == dialogResult) 
     interaction.SetOutput(vm.SelectedNumber); 
    else 
     interaction.SetOutput(-1); 
}); 

OpenDialog = ReactiveCommand.Create(() => 
{ 
    GetNumberFromDialog.Handle(Unit.Default) 
     .Where(retVal => -1 != retVal) // If the dialog did not return true, don't update 
     .Subscribe(retVal => 
     { 
      this.MyNumber = retVal; 
     }); 
}); 

ステップ:

  1. プロジェクトを実行します。 -5000のラベルに注意してください。これは更新する番号です。
  2. [ダイアログを開く]ボタンをクリックします。ダイアログウィンドウが開きます。
  3. ListBoxで数値を選択します。 「現在の選択」の下のラベルが更新されます。これはListBox.SelectedItemと同じ値にバインドされています。
  4. [OK]をクリックします。ダイアログが閉じます。

予想される動作:「マイナンバー」の下にあるメインウィンドウのラベルは、ListBoxで選択した値に更新する必要があります。

実際の動作:ラベルは0(デフォルト値はint)に更新されます。

ダイアログが閉じたときに自分のViewModelがリセットされるのはなぜですか?

答えて

1

GitHubでサンプルを見ると、問題が明らかになります。あなたのDialogWindowは次のようになります。あなたのMainWindowViewModel

public partial class DialogWindow : Window, IViewFor<DialogWindowViewModel> 
{ 
    public DialogWindow() 
    { 
     InitializeComponent(); 
     this.ViewModel = new DialogWindowViewModel(); 
     this.DataContext = this.ViewModel; 

     this.ViewModel 
      .WhenAnyValue(x => x.DialogResult) 
      .Where(x => null != x) 
      .Subscribe(val => 
      { 
       this.DialogResult = val; 
       this.Close(); 
      }); 
    } 

    public DialogWindowViewModel ViewModel { get; set; } 
    object IViewFor.ViewModel 
    { 
     get => ViewModel; 
     set => ViewModel = (DialogWindowViewModel)value; 
    } 
} 

、あなたはあなたのDialogWindowViewModel新しいインスタンスにDialogWindow.ViewModelプロパティを設定します。この時点で問題が発生しています。あなたの問題は、DialogWindow.ViewModelプロパティを設定するとではなく、はビューのDataContextを設定するか、またはWhenAnyValueを再現することです。これは、ビューが依然としての古いインスタンス(DialogWindowコンストラクタで作成されたもの)のSelectedNumberプロパティにバインドされていることを意味します。上記のサンプルコードを修正するには、単にViewModelプロパティの設定を避け、ダイアログに既に設定されているViewModelを使用します:

GetNumberFromDialog.RegisterHandler(interaction => 
{ 
    // Get a reference to the view for this VM 
    var view = Locator.Current.GetService<IViewFor<DialogWindowViewModel>>(); 

    var window = view as Window; 
    var dialogResult = window.ShowDialog(); 

    // use the ViewModel here that's already set on the DialogWindow 
    if (true == dialogResult) 
     interaction.SetOutput(view.ViewModel.SelectedNumber); 
    else 
     interaction.SetOutput(-1); 
});