我应该如何在MVVM中处理这种常见的UI场景?

时间:2010-08-20 14:55:59

标签: wpf user-interface mvvm

情景:

  1. 父窗口加载,填充数据(网格,标签等)
  2. 用户单击按钮,在父窗口的ViewModel中触发绑定命令,启动编辑对话框
  3. 用户在编辑对话框中进行更改,然后单击“接受”,将一些信息保存到数据库
  4. 父窗口的ViewModel识别出发生了某些事情(注意到dialog.DialogResult == true),并且它应该刷新它的数据和任何相关的绑定
  5. 还要考虑步骤3可能由于某种原因而失败(复杂的业务逻辑规则可能会失败并且用户需要调整某些内容,数据库更新可能会引发异常,僵尸入侵等),因此编辑对话框可能有保持开放。

    ViewModels不应该(根据我的理解)知道很多关于其相关View的内容,因此,ViewModel很难与View进行通信:

      

    “嘿,保存操作成功完成!继续关闭吧!”

    或者:

      

    “哇!在你关闭之前有一个问题需要注意......等一下。”

    问题:

    如何使用xaml.cs代码(最好没有代码)完成优雅这样的事情?

4 个答案:

答案 0 :(得分:3)

通常在执行此类操作时,我会将对话框窗口的打开关闭到服务,以后可以进行模拟以进行测试。类似的东西:

public interface IDialogProvider
{
      bool OpenDialog(IViewModel viewModel)
}

然后传入的viewmodel可以绑定设置为模态窗口的DataContext,并且通过数据模板化将使用正确的视图。

当触发命令打开子项时,父视图模型可以使用此服务。孩子可以完成所需的所有处理,并且可以从孩子那里获得所需的任何信息,以获得真实的结果:

public void ExecuteEdit()
{
    ChildViewModel childViewModel = GetViewModelForSelectedItem();
    if (_dialogProvider.OpenDialog(childViewModel)
    {
        //child view model saved, trigger rebinding etc...
    }
}

如果你有这些对话框使用的视图模型的特定基类来处理错误场景,你可以使用一些代码来处理关闭窗口。我在视图模型中使用视图不可知事件,并在触发此事件时关闭窗口。在视图中:

public DialogWindowView()
{
    InitializeComponent();
    DataContexctChanged += HandleDataContextChanged;
}

private void HandleDataContextChanged(object sender, EventArgs e)
{ 
    IDialogViewModel viewModel = DataContext as IDialogViewModel;

    if (viewModel != null)
    {
         viewModel.ActionSuccessful += HandleActionSuccessful
    }
}

private void HandleActionSuccessful(object sender, EventArgs e)
{
     DialogResult = DialogResult.OK;
     Close();
} 

我完全没有问题,因为这个代码是视图,因为viewmodel不负责处理事物的样子,包括打开或关闭窗口。如果你完全反对代码背后的想法,或者你不想将视图耦合到viewmodel类型,你可以将责任转移到DialogProvider:

public class DialogProvider : IDialogProvider
{
  public bool OpenDialog(IDialogViewModel viewModel)
  {
       Window dialog = new DialogWindow();
       dialog.DataContext = viewModel;
       bool success = false;
       viewModel.ActionSuccessful = (o, e) => 
         {
              dialog.Close();
              success = true;
         }

      dialog.ShowDialog();

      return success;
  }
}

答案 1 :(得分:1)

您的EditDialog可能具有IsVisible属性,对话框可见性绑定到该属性。如果保存失败,请将IsVisible属性设置为true,否则将其设置为false。由于它是绑定的,它应该在保存成功时自动隐藏Popup,或者如果失败则保持打开。

答案 2 :(得分:1)

好问题。
MVVM模式声明View应该数据绑定到ViewModel.Properties。 View可以通过调用ViewModel.Commands(View => VM)来触发操作 因此,ViewModel将某些内容传递回View的唯一方法是通过Properties(即PropertyChangedNotifications)。视图必须绑定到VM上的某个属性并进行更改,以决定是否自行关闭。

答案 3 :(得分:0)

我滚动了我自己的窗口加载器,我在这里的回答中有描述:

Managing multiple WPF views in an application