2013-02-08 104 views
10

我在我们的WPF应用程序中使用MVVM模式以允许进行全面的单元测试。 MVVM模式本身工作得很好,但是我正在努力调整模式,这意味着我可以使用WPF的设计时数据支持。在MVVM模式中使用WPF设计数据

正如我使用棱镜的视图模型实例通常注入到视图的构造,像这样

public MyView(MyViewModel viewModel) 
{ 
    DataContext = 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中设置这些属性,我还经常需要更改其他属性,以使其具有setter或可修改的集合。

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

这是令人担忧的我:

  • 我有一个从未想过会叫,不进行单元测试
  • 有房产setter方法参数的构造函数,只有视图模型本身应该被称为
  • 我的ViewModel现在是一个混乱的属性,应该由视图修改,那些不应该 - 这使得它很难告诉一眼看哪段代码负责维护任何给定的属性
  • 在设计时设置某些属性(例如在Filter文本中看到样式)实际上最终可能会调用ViewModel逻辑! (所以我的视图模型也需要tollerant否则强制依赖是在设计时失踪)

有没有更好的方式来获得的方式,不影响在WPF MVVM应用程序设计时数据我ViewModel以这种方式?

另外,我应该建立我的ViewModel不同,以便它具有更多的简单属性与逻辑分离出其他地方。

回答

-1

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

在我的版本中,我创建了MVVM模型FIRST,并且可以对它进行单元测试,直到母牛回家并且不用担心任何视觉设计......如果模型被破坏,视觉实现也将如此。在我的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(); 
    } 
} 

希望这有助于替代您所遇到的情况。

+2

对我来说有点奇怪,你的虚拟机会依赖于你的视图。 – 2013-02-09 21:58:06

+0

@GregD,而不是我。我应该能够拥有这个模型,我可以查询数据,通过暴露getter/setter设置可能呈现给任何外部“视图”的标志。我只是说在这个例子中,它并不需要视图,但是如果我想启动一个视图,每个视图模型都有自己的目的,比如维护屏幕,事务头/细节处理等等。如果有相应的视图,我只需要说钩子...去调​​用与此mvvm处理程序关联的视图。 – DRapp 2013-02-10 01:25:57

+0

那么设计时数据如何使用这种方法呢? – Justin 2013-02-10 18:55:01

1

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

在我身边,我只用棱镜位,和我的模型和视图模型总是提供空白构造函数(像什么布赖恩显示),数据上下文在视图中的XAML分配,我设置的属性值,如:

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

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

    UseMyView(); 
} 

这种方法的另一个好处是,视图模型在设计创建一次,使用相同的路径和运行时间,让你产生更少的对象和保存GC的努力。我觉得这很优雅。

至于到制定者,如果你让他们私人的设计数据仍然可以工作,如:

public string MyProp { get; private set; } 

好吧,对其进行自定义在您方便的管理NotifyPropertyChange,但你的想法。

现在,我还没有一个解决方案来管理ObesrvableCollection s(我面临同样的问题,虽然在XAML中有多个值有时可以工作......),是的,我同意你必须在未设置属性时管理案例,例如在构造函数中设置默认值。

我希望这会有所帮助。