ReactiveUI:从自定义对话框返回值

时间:2017-12-06 18:09:10

标签: c# wpf mvvm reactiveui

我有一个窗口,它使用ReactiveUI Interaction打开第二个窗口作为模式对话框,然后在第二个窗口中从ListBox返回数据。

问题是当.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. 点击&#34;打开对话框&#34;按钮。将打开一个对话框窗口。
  3. 在ListBox中选择一个数字。请注意&#34;当前选择&#34;下的标签;更新 - 这与ListBox.SelectedItem。
  4. 绑定的值相同
  5. 单击“确定”。对话框关闭。
  6. 预期行为:主窗口中的标签&#34;我的号码是&#34;应更新为您在ListBox中选择的值。

    实际行为:标签更新为0(int的默认值)。

    为什么我的ViewModel会在对话框关闭时自行重置?

1 个答案:

答案 0 :(得分:2)

在GitHub上查看您的示例有助于揭示问题。您的DialogWindow看起来像这样:

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

MainWindowViewModel中,您将DialogWindow.ViewModel属性设置为DialogWindowViewModel实例。这个问题在这一点上很突出。您的问题是设置DialogWindow.ViewModel属性设置视图DataContext或重新创建WhenAnyValue可观察对象。这意味着视图仍然绑定到SelectedNumber实例上的DialogWindowViewModel属性(在DialogWindow构造函数中创建的实例)。要修复上面的示例代码,您可以简单地避免设置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);
});