2016-08-17 104 views
0

我最近试图重写一个WinForm应用程序到WPF。我一直在试图在我的应用程序中实现一个MVVM结构,因为它开始看起来很像Winforms,我需要命名我的控件x:Name并且始终引用它们。实质上,我没有使用MVVM提供的功能。MVVM和WPF结构

有一件事情我无法绕包头,是Window。每次创建一个窗口时,它都会生成一个部分类。我的问题是,这与MVVM有什么关系?这个类应该包含什么内容会引起混淆。它是否有一个DataContext绑定?按钮事件怎么样?

从我的理解(目前),是这个“部分”类应该有很小的代码,也许只有绑定你ViewModel在构造函数:

this.DataContext = new ViewModel(); 

和其他的功能应该来自ViewModelXAML绑定事物的帮助。然而,每个ViewModel应该连接到一个单一的Model。但是当这个特定的窗口需要许多模型时会发生什么,例如客户端,产品等?你做一个单独的ViewModel类,以某种方式做一切?

我的问题的本质在于此部分“偏”类的内容及其与ViewModel的关系。

+0

UI逻辑进入代码隐藏,业务逻辑进入您的视图楷模。你的绑定和DataTemplates将处理你必须在winform中完成的大部分UI玩杂耍,但是如果你创建了自定义控件,你将会添加任何他们需要运行的代码到他们的代码隐藏中。 – Will

回答

2

看起来你有两个问题:

  1. 如何赫克没有这部分类的东西适合与MVVM?
  2. 如何构建所有视图模型和模型以及内容?

1)在讨论WPF时,你所说的“部分类”通常被称为“代码隐藏”。这是因为在非MVVM模式中,它通常具有所有位于xaml布局背后的实际C#代码 - 即“代码隐藏”。

你是正确的,一个好的MVVM实现一个很好的迹象是最小/无代码隐藏。正如你所提到的,通常它将把DataContext绑定到ViewModel上 - 在很多框架中,这些都是为你处理的,你甚至不需要这些。在我的MVVM项目各部分的类看起来是这样的:与MVVM的好处

namespace MyApp.Views 
{ 
    public partial class GeneratorView : CreatableView 
    { 
     public GeneratorView() 
     { 
      InitializeComponent(); 
     } 
    } 
} 

部分原因是,所有你不得不在的WinForms意大利面条事件更新/连接代码全部由使用绑定绕过。但正如你所说,你仍然可以用WPF来做到这一点,但它通常被认为是不好的做法,绝对是MVVM。

与所有内容和命令直接通过数据绑定绑定到视图模型,部分类不必具有任何内容都没有。有很多的解释,但在基本的水平上:

  • 该视图奠定了事情,并在屏幕上显示的东西。
  • 视图模型包含UI特定的数据和逻辑。它处理来自视图的命令,并可能使用业务服务。
  • 该模型表示您的数据。考虑一下数据库或文件系统中的内容。

2)MVVM是不是在你如何构建它严格。一般来说,约定是每个视图都有ViewModel。不过,我相信没有View的ViewModel可以。特别简单的。

但是当这个特殊的窗口调用许多模型时会发生什么,如客户端,产品等?你做了一个单一的ViewModel类,以某种方式做一切?

一点都没有,看起来好像你已经拥有了这个全有或全无的单片ViewModel。如果这些真的很简单的结构,我会做这样的:

enter image description here

但是,您可能需要一个专门的ClientView或ProductView中,而是将它们嵌入在主视图:

enter image description here

关键是您的ViewModels可能包含其他ViewModels,ViewModels数组。同样,您的视图可以嵌入其他视图来显示它的ViewModels - 或者不。如果他们很简单,或者你只是说,列出一些属性(也许当你点击'信息'按钮时,会出现一个对话框,它具有ViewModel的完整视图,但是在列表中只需要名称和成本

这很灵活,关于这个问题,通常Window甚至不是MVVM模式的一部分,它非常“愚蠢”,甚至没有ViewModel(另外,如果你想要)

拥有一个高级别的“AppViewModel”并且你所有的窗口都包含它(通常甚至不会打扰WindowViewModel,这实际上并不是一个问题) 。

+0

写得很好,简洁!第二张图片描述了我的问题:一个包含其他视图模型的ViewModel。但是,如果WindowViewModel中有其他视图模型,比如说六个,该怎么办?不应该有一种方法来在WindowViewModel中创建依赖注入吗? – Dimitri

+0

这六个View-ViewModel是否同时显示?你期望他们改变吗?在我的应用程序中,我有一个中央ViewModel,它包含navagation(向前,向后,父页面,子页面列表等)并管理它们的显示。顺便说一句,我将它作为一个“PageController”注入到页面中,该页面具有“DisplayPage(BasePageViewModel页面)”方法。这种高级应用程序/显示结构全部使用IBasePageViewModels完成。这些页面本身非常特殊,你不能真正注入它们的内容(除非它们只是聚集一堆视图)。 – Joe

+0

真的那种东西不仅仅是MVVM,而是更广泛的应用程序设计。依赖注入是关于注入服务。Child ViewModels并不是真正的服务,在我看来,不应该使用DI注入,除非他们正在执行服务 - 但即使如此,它也应该可以从ViewModel理想地提取出来。 – Joe

1

您可以在视图模型中使用多个模型。视图模型的目标是从业务层(模型,服务)中抽象出来。

创建和保留实例可以使用IoC(控制反转)容器。有许多IoC容器可用于.NET应用程序,例如Castle Windsor,Autofac等(请参阅List of .NET Dependency Injection Containers (IOC))。你只需要通过必要的模型对象创建一个视图模型对象,比如像这样:

public class ViewModel 
{ 
    private readonly IClientModel _clientModel; 
    private readonly IProductModel _productModel; 

    public ViewModel(IClientModel clientModel, IProductModel productModel) 
    { 
     _clientModel = clientModel; 
     _productModel = productModel; 
    } 

    // Logic of your view model 
} 

还需要配置对象的依赖和范围(你的模式将是一个单身或类型的新实例) 。容器在创建对象时会注入依赖关系。

另外我建议阅读文章MVVM - IOC Containers and MVVM

+0

好吧,我想这里的主要问题是:这种情况下的视图是什么?如果我有一个窗户,那是否被视为一个视图?在这个窗口中,我有几件事情,标签,文本框,它们是完全不相关的:它们会被视为“视图”吗? – Dimitri

+0

查看是xaml文件。它可能是窗口,组件等等。视图模型通过绑定到视图的相应标签,文本框和其他控件来提供数据。 – Didgeridoo

+0

我明白了。所以在我的主窗口(使用我的MainViewModel)中,我可以有多个视图实例(就像你已经展示的那样)并且简单地将它们绑定到适当的DataContext上? – Dimitri

1

是的,无论如何,我的方式是保持我的窗户哑。多么愚蠢?我想这取决于应用程序。如果我只是试图抛出一个概念证明或者低重要性的东西,那么我会削减几个角落。如果我正在开发一个需要维护的大型应用程序,那么我会变得更加严格,在这种情况下,我甚至可能会对构造函数中的ViewModel设置不满。

但是,每个视图模型应该连接到一个单一的模式

我不知道,我同意这一点。无论如何,这并不是我接触MVVM的方式。我会说,每个视图都应该绑定到ViewModel。在ViewModel中,可能出现这种情况,你只能处理一个模型,但使用单个ViewModel也可以以一致的方式将多个模型展示给一个View。

下面是我用作一些小型项目中的跳板点的模板示例。我喜欢在我的窗口和视图中使用明确的ViewModel属性,但您不必;你可以修改它来代替使用DataContext属性。

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    public object ViewModel 
    { 
     get { return (object)GetValue(ViewModelProperty); } 
     set { SetValue(ViewModelProperty, value); } 
    } 
    public static readonly DependencyProperty ViewModelProperty = DependencyProperty.Register(
     "ViewModel", 
     typeof(object), 
     typeof(MainWindow)); 
} 

ViewModel propoerty后面的代码只是窗口的依赖项属性。我将把Window内容绑定到这个属性。在这种情况下,它是一个object,但它可以是一些基本的ViewModel类或一个接口,如果你想。

在我窗口的标记我想补充一个DataTemplate每个视图模型到窗口的资源。如果所有东西都连接正确WPF的隐式数据模板将接管并确保在ViewModel属性发生更改时呈现正确的视图。

<Window x:Class="Example.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:system="clr-namespace:System;assembly=mscorlib" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:viewModels="clr-namespace:Example.ViewModels;assembly=Example" 
     xmlns:views="clr-namespace:Example.Views;assembly=Example"> 

    <Window.Resources> 
     <ResourceDictionary> 
     <DataTemplate DataType="{x:Type viewModels:FirstViewModel}"> 
      <views:FirstView ViewModel="{Binding }" /> 
     </DataTemplate> 
     <DataTemplate DataType="{x:Type viewModels:SecondViewModel}"> 
      <views:SecondView ViewModel="{Binding }" /> 
     </DataTemplate> 
     </ResourceDictionary> 
    </Window.Resources> 

    <Grid> 
     <ContentControl HorizontalAlignment="Stretch" 
         VerticalAlignment="Stretch" 
         Content="{Binding ViewModel, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" /> 
    </Grid> 
</Window> 
+1

显示多个ViewModel的ViewModel怎么样?假设有一个窗口可以绑定MainViewModel。还要说这个窗口的不同部分有不同的视图,需要他们自己的ViewModels。是否可以在MainViewModel中保存多个视图模型并执行如下操作: