10

我在我们的 WPF 应用程序中使用 MVVM 模式来进行全面的单元测试。MVVM 模式本身运行良好,但是我正在努力适应模式,这意味着我可以使用 WPF 的设计时数据支持。

当我使用 Prism 时,通常会将 ViewModel 实例注入到视图的构造函数中,就像这样

public MyView(MyViewModel viewModel)
{
    DataContext = viewModel;
}

然后将 ViewModel 的依赖项注入到构造函数中,就像这样

public class MyViewModel
{
    public MyViewModel(IFoo foo, IBar bar)
    {
        // ...
    }

    // Gets and sets the model represented in the view
    public MyModel { get; set; }

    // Read-only properties that the view data binds to
    public ICollectionView Rows { get; }
    public string Title { get; }

    // Read-write properties are databound to the UI and are used to control logic
    public string Filter { get; set; }
}

这通常工作得很好,除非涉及到设计数据 - 我想避免将设计数据特定类编译到我发布的程序集中,所以我选择使用该{d:DesignData}方法而不是该{d:DesignInstance}方法,但是为了使其正常工作我的ViewModel 现在需要有一个无参数的构造函数。此外,为了能够在 XAML 中设置这些属性,我还经常需要更改其他属性以具有设置器或成为可修改的集合。

public class MyViewModel
{
    public MyViewModel()
    {
    }

    public MyViewModel(IFoo foo, IBar bar)
    {
        // ...
    }

    // Gets and sets the model represented in the view
    public MyModel { get; set; }

    // My read-only properties are no longer read-only
    public ObservableCollection<Something> Rows { get; }
    public string Title { get; set; }

    public string Filter { get; set; }
}

这让我很担心:

  • 我有一个无参数的构造函数,它永远不会被调用,也没有经过单元测试
  • 有一些属性的设置器,只有 ViewModel 本身应该调用
  • 我的 ViewModel 现在是应该由视图修改的属性和不应该修改的属性的混合体——这使得一眼就很难判断哪段代码负责维护任何给定的属性
  • 在设计时设置某些属性(例如查看Filter文本样式)实际上最终会调用 ViewModel 逻辑!(所以我的 ViewModel 还需要容忍在设计时缺少其他强制依赖项)

有没有更好的方法在 WPF MVVM 应用程序中获取设计时数据,并且不会以这种方式损害我的 ViewModel?

或者,我是否应该以不同的方式构建我的 ViewModel,以便它具有更简单的属性,并将逻辑分离到其他地方。

4

2 回答 2

2

首先,我建议您看一下这个视频,其中 Brian Lagunas 提供了一些关于 MVVM 的最佳实践。Brian - 至少 - 参与了 Prism 的开发,因为他的名字出现在 nuget 包信息中。没有进一步检查。

在我这边,我只使用了一些 Prism,我的 Model 和 ViewModel 总是提供空白构造函数(就像 Brian 展示的那样),数据上下文在视图的 XAML 中分配,我设置的属性值如下:

<MyView.DataContext>
  <MyViewModel />
</MyView.DataContext>

public void BringSomethingNew()
{      
  var myView = new View();
  (myView.DataContext as ViewModel).Model = myModel;

  UseMyView();
}

这种方法的另一个好处是 ViewModel 只创建一次,在设计和运行时具有相同的路径,因此您创建的对象更少并节省了 GC 工作。我觉得这很优雅。

至于设置器,如果您将它们设为私有,设计数据仍然可以使用,例如:

public string MyProp { get; private set; }

好的,自定义它以便NotifyPropertyChange在您方便时进行管理,但您已经明白了。

现在,我还没有管理ObesrvableCollections 的解决方案(我面临同样的问题,尽管在 XAML 中放置多个值有时会起作用...... ???),是的,我同意你必须在未设置属性,例如在构造函数中设置默认值。

我希望这有帮助。

于 2016-12-01T13:34:44.233 回答
-1

我也曾使用 WPF 和 MVVM 实现进行 NUnit 测试。但是,我的版本与您的相反。您首先创建视图,然后创建模型来控制它。

在我的版本中,我首先创建了 MVVM 模型,并且可以对其进行单元测试,直到奶牛回家,而不用担心任何视觉设计……如果模型坏了,那么视觉实现也会坏掉。

在我的 MVVM 模型中,我有一个“GetTheViewWindow”的方法。因此,当我从我的 MVVM 基线派生时,每个视图模型都有自己负责的视图。所以通过虚拟方法,每个实例在被应用到生产时都会做自己的新视图窗口。

public class MyMVVMBase
{
   private MyViewBaseline currentView;

   public MyMVVMBase()
   { // no parameters required }

   public virtual void GetTheViewWindow()
   { throw new exception( "You need to define the window to get"; ) }
}

public class MyXYZInstanceModel : MyMVVMBase
{
   public override void GetTheViewWindow()
   {
      currentView = new YourActualViewWindow();
   }
}

希望这有助于替代您遇到的问题。

于 2013-02-08T18:12:29.357 回答