【问题标题】:WPF MVVM and passing viewmodels to a viewWPF MVVM 并将视图模型传递给视图
【发布时间】:2014-09-02 07:50:37
【问题描述】:

我对 WPF 很陌生,现在我正在尝试习惯 MVVM 模式。现在我有一个简单的应用程序,其中我有一组视图模型,我在网格中显示。当我双击网格中的行时,我想显示 ViewModel 的详细信息视图。

我现在遇到的问题是我已经有一个完全实例化的 ViewModel,但我似乎无法将它传递到视图中。当我尝试加载该视图时,它变成了空的。我已经发现这是因为当一个 View 被加载时,它会创建它自己的支持 ViewModel 的实例。所以很明显,我需要解决这种行为,并在创建时以某种方式将实例化的 ViewModel 传递到 View 中。我可以在 View 中使用一个构造函数,该构造函数采用 ViewModel 并在其中设置数据源。但是,采用这种方法意味着我需要在 ViewModel 中构造 View,从而使 ViewModel 了解 View。这是我想避免的事情,因为我试图维护 MVVM 模式。

那么在这种情况下我该怎么办?我应该打破 MVVM 模式,还是有一些适合 MVVM 模式的漂亮干净的解决方案?

【问题讨论】:

    标签: wpf mvvm


    【解决方案1】:

    有很多方法可以将视图模型传递给视图,正如您所说,或者将视图模型设置为WindowUserControlDataContext,如其他人可能会这样称呼它。最简单的就是这样:

    在视图构造函数中:

    public partial class SomeView
    {
        InitializeComponent();
        DataContext = new SomeViewModel();
    }
    

    更多的 MVVM 方法可能是在 App.xaml 中为每个定义每个将使用哪个视图的视图模型定义 DataTemplates:

    <DataTemplate DataType="{x:Type YourViewModelsPrefix:YourViewModel">
        <YourViewsPrefix:YourView />
    </DataTemplate>
    ...
    <DataTemplate DataType="{x:Type YourViewModelsPrefix:AnotherViewModel">
        <YourViewsPrefix:AnotherView />
    </DataTemplate>
    

    现在,每当框架遇到这些视图模型类的实例时,它就会呈现相关的视图。您可以通过使用 ContentControl 的视图模型类型的属性来显示它们,如下所示:

    <ContentControl Content="{Binding YourViewModelProperty}" />
    

    甚至在这样的集合中:

    <ListBox ItemsSource="{Binding YourViewModelCollectionProperty}" />
    

    【讨论】:

      【解决方案2】:

      “我应该打破 MVVM 模式吗?”

      好吧,请考虑进一步了解该模式,了解“打破它”是什么。这种模式的主要目的是保持责任清晰,从而获得可测试和可维护的代码。如这个问题所示,有很多资源: MVVM: Tutorial from start to finish?

      无论如何要更具体地了解您的问题,您正在寻找的是如何设置 DataContext。

      “在创建时以某种方式将实例化的 ViewModel 传递给 View”

      是的,你明白了,如果你在视图的构造函数中为 dataContext 分配一个 viewModel,它可以工作,但只有当 viewModel 有责任创建视图时它是可以接受的(这实际上是可以接受的少数情况)。您甚至可以编写类似的东西来直接从您的视图之外设置 DataContext:

      var l_window = new MyView { DataContext = new MyViewModel() };
      l_window.Show();
      

      当然,主要缺点是这段代码不可测试。如果您想对其进行测试,您应该使用可模拟服务来管理视图创建。

      更常见的解决方案是使用 IOC 容器(如 prism)注入 dataContext。您在软件启动时创建所有必需的 ViewModel,并将它们存储在此 IOC 容器中。然后,当创建视图时,您要求此容器为您获取 viewModel 的实例。

      一个例子可能是:在 PRISM 中导出您的 viewModel:

      [Export]
      public class MyViewModel {...}
      

      然后在你的视图中导入它:

      [Import]
      private MyViewModel ViewModel
      {
      set { this.DataContext = value; }
      get { return this.DataContext as MyViewModel; }
      }
      

      希望对你有帮助。

      【讨论】:

        【解决方案3】:

        我同意@Sheridan 的回答,并且只想添加另一种使用视图模型实例化视图的方法:您可以使用工厂模式,也许像这样:

        public class ViewFactory
        {
            public UIElement Create(object context)
            {
                // Create the view model
                // You can pass in various information by parameters
                // as I do with context (Constructor Injection)
                var viewModel = new ViewModel(context);
        
                // Create the view and set the view model as data context
                var view = new View { DataContext = viewModel };
                return view;
            }
        }
        

        您可以从视图模型的方法中调用此工厂,然后将其分配给例如一个属性,它是绑定到 UI 的数据。这允许更多的灵活性 - 但@Sheridan 的解决方案也很好。

        【讨论】:

          猜你喜欢
          • 2012-05-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-22
          • 1970-01-01
          • 1970-01-01
          • 2019-02-01
          相关资源
          最近更新 更多