2017-12-06 12 views
2

ReactiveUI 상호 작용을 사용하여 두 번째 창을 모달 대화 상자로 여는 창에서 두 번째 창에서 ListBox의 데이터를 반환합니다.ReactiveUI : 사용자 지정 대화 상자에서 반환 값

.ShowDialog()가 완료되면 ViewModel의 SelectedItem은 항상 null로 평가됩니다. 바인딩이 올바르게 작동하고 선택한 항목이 대화 상자의 ViewModel에서 올바르게 업데이트되고 있음을 확인했습니다. 상호 작용으로 돌아와서 속성이 기본값 (null)으로 재설정되는 경우에만 해당합니다.

내가 함께 여기에 문제의 최소한의 예를 넣었습니다 : 시험

https://github.com/replicaJunction/ReactiveDialogTest

주요 논리는 MainWindowViewModel.cs입니다.

편집 :

  1. 프로젝트를 실행 :
    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; 
         }); 
    }); 
    

    단계

    문제를 재현하기 : 여기에 기본적인 아이디어와 코드에서 코드 조각입니다. -5000의 레이블을 주목하십시오 - 업데이트 할 번호입니다.
  2. "대화 상자 열기"버튼을 클릭하십시오. 대화 상자 창이 열립니다.
  3. ListBox에서 숫자를 선택하십시오. "Current Selection"아래의 레이블은 ListBox.SelectedItem과 동일한 값으로 바인딩됩니다.
  4. 확인을 클릭하십시오. 대화 상자가 닫힙니다.

예상되는 동작 : "내 번호가 있음"아래의 주 창의 레이블은 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을 다시 관찰 할 수 있다는 것입니다. 이는 뷰가 여전히 DialogWindowViewModel (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); 
});