【问题标题】:Right Way to access a View Model from an existing View Model从现有视图模型访问视图模型的正确方法
【发布时间】:2010-10-31 18:45:37
【问题描述】:

我对 MVVM 有点陌生。我不确定最好的方法是做我想做的事。

这是场景:

我有一个要显示另一个窗口的虚拟机。我可以打电话给myNewWindowView.Show(),但首先我需要在我的新窗口的虚拟机中设置一些数据。

我应该将 myNewWindowViewNewWindowViewModel 都暴露给调用 ViewModel 吗?

这是一个例子:

class MainVM
{
    public void FindCustomer(string nameParial)
    {
       List<Customer> customers = ServiceCall.GetCustomers(nameParital);
       // This is the part I am not sure how to do.  I am not sure if this
       //  View Model should have a reference to a different view model and
       //  the view too.
       myNewWindowViewModel.CustomerList = customers;
       myNewWindowView.Show();
    }
}

【问题讨论】:

    标签: c# wpf mvvm prism


    【解决方案1】:

    我会将视图模型与任何视图分开。我倾向于将它们视为层,但它们只能在一个方向上互换。

    因此,foo 类型的模型可以在其上分层放置任何视图模型,并且它从不期望或关心视图模型类型。

    一个视图模型只能用于一种类型的模型,但它并不关心或期望什么类型的视图会使用它。

    视图将用于特定类型的视图模型。

    您似乎拥有的是一个视图模型,它关心视图在做什么,这对我来说似乎是错误的。

    如果是我,我会让 MainVM 的视图显示新窗口,让 MainVM 为新窗口传递适当的视图模型。

    这是我要放在主视图模型视图后面的代码

    class MainWindow : Window
    {
         public MainWindow()
         {
              Initialize();
              DataContext = new MainVM();
         }
    
         public void FindCustomerClick(object sender, RoutedEventArgs args)
         {
              CustomerListView clv = new CustomerListView();
              clv.DataContext = (DataContext as MainVM).FindCustomer(search.Text);
              clv.Show();
         }
    }
    

    如您所见,viewmodel 有一个方法,该方法接受一个字符串并返回一个 CustomerListViewModel,然后将其应用于 CustomerListView 的 DataContext。

    【讨论】:

    • 听起来不错,但听起来也很模糊。你能告诉我一个你如何正确地做我的例子的例子吗? (即,让一个窗口打开另一个窗口,并在它们之间传递一些数据。)
    • 我会试试的。我可能需要稍后修复它,因为我正在通过手机进行此操作:)
    • 这看起来不错,只是我的CustomerListView.DataContext 设置为我的CustomerListViewModel。如果我设置为 FindCustomer 的结果,那么我将丢失该视图的 MVVM 设置。
    • 在我的示例中,CustomerListView 是视图的一个新实例,因此它不会影响您已经创建的任何其他实例。如果您有一个主 CustomerListView,那么在新视图中对客户的任何更改都应通过底层 Customer 模型类传播。
    【解决方案2】:

    不要在视图模型中引用视图。让视图创建视图,让视图模型创建视图模型。

    实现这种关注点分离的一种简单方法是使用事件。快速而肮脏的方法是在父视图模型上创建ChildViewModel 属性,然后在视图中处理PropertyChanged,例如:

    ParentViewModel vm = (ParentViewModel)DataContext;
    vm.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "ChildViewModel")
        {
            MyChildWindow w = new MyChildWindow();
            w.Show(vm.ChildViewModel);
        }
    };
    

    现在每次父视图模型更改ChildViewModel 属性时,父视图都会打开一个新的子视图。

    一种不那么快速且不那么脏的方法是创建一个CreateViewEventHandler 委托和CreateViewEventArgs 类,并使事件处理程序和一个受保护的OnCreateView 方法成为基本视图模型类的一部分(假设您有一个)。这允许视图模型更明确地说明何时应该创建子窗口。

    请注意,如果父视图模型知道子视图模型何时关闭很重要,则子视图模型可以公开父视图模型可以订阅的事件(或者,再次使用属性和PropertyChanged事件)。

    请注意,在这两种情况下,您都可以编写单元测试来验证视图模型是否会在不涉及视图的情况下打开窗口(即引发事件)。

    我自己没有使用过任何 MVVM 框架,但我看过的那些具有旨在促进此类事情的消息传递工具。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-15
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      • 2018-06-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多