WPF - 首先是MVVM视图模型

时间:2015-02-10 14:43:43

标签: c# wpf xaml mvvm

我正在构建一个大型WPF应用程序 - 一种托管多个模块的桌面,例如通过RS232 /以太网的多个终端窗口,寄存器分析器,自动化工具等。  我正在使用MVVM架构,其中我的视图(XAML)在其资源部分中实例化corespondent viewmodel。并且视图模型在视图的数据上下文中设置。 在此方法中,视图首先创建。

然而,我首先想到了另一个名为VM的方法,这意味着视图模型在视图之前被实例化,我理解了它背后的理论。我不明白的是何时和谁实例化视图以及如何在不耦合视图的情况下发生。

我会非常高兴听到您的想法,如果有人可以提供代码示例,那就太棒了。

提前致谢。

4 个答案:

答案 0 :(得分:0)

我在我的项目中大量使用MVVM,可以分享我对此的看法。 在我的项目中,视图从不实例化任何VM。通常我会有某种管理器,它会注意创建相应的VM。

这是我分配给某些顶级UI控件(例如Window)的datacontext。视图始终由目标类型设置为视图模型类型的样式定义。 启动代码只创建一个Window和主视图模型。 VM已分配,其余部分由WPF(.net)运行时完成。

所以我有一个大型样式文件,每个viewmodel的所有样式都定义了相应的视图(通常是一个usercontrol)。

这就是我做事的方式,其他人肯定也是如此。

HTH

答案 1 :(得分:0)

当您的应用程序增长时,您通常会面临这些决定。通常,"始终" 这两个元素一起ViewViewModel它不是关于什么是第一个它更多就像你将用什么来实例化这两个元素(viewviewmodel)。 对于较大的项目,当我有需要时,我使用了一个名为ViewModelResolver的类。它显然有一个接口IViewModelResolver所以它可以很好地注入。 它可以根据基于类型的约定或字符串表示返回ViewModel,并使用反射来实例化它。 您还可以传入ViewModel(或类型)并将匹配的view与传递的view model作为DataContext(查看ViewModel婚姻),或者您可以定义其他自定义实例化viewViewModel所需的方案。

希望有所帮助

所以主要的是要有一个中间类,它起到某种工厂服务的作用,它可以带动视图并一起查看模型并实例化它们。 这为您提供了更多的自由,也是您直接从ViewModel中分离出这些决策的好地方。

答案 2 :(得分:0)

在我的WPF / MVVM应用程序中,我使用带有两个构造函数的ViewModels - 一个用于设计时间(没有参数 - 直接设置所需组件的模拟版本),另一个用于运行时(所需组件通过IoC作为参数注入)。这允许(模拟)数据显示在Visual Studio设计器中以进行UI测试。

所以简单的案例看起来像......

public class MainViewModel : ViewModelBase
{
    private IDataFactory _DataFactory;

    public MainViewModel()
    {
        _DataFactory = new DesignTimeMockDataFactory();
        LoadData();
    }

    [PreferredConstructor]
    public MainViewModel(IDataFactory dataFactory)
    { _DataFactory = dataFactory; }

    public void LoadData()
    { DataItems.AddRange(_DataFactory.GetDataItems()); }

    public ExtendedObservableCollection<DataItem> DataItems { get; private set; }
}

设计时间用法可以直接在XAML中设置......

<Window x:Class="MainView"
        d:DataContext="{d:DesignInstance Type=MainViewModel, IsDesignTimeCreatable=True}"
...

运行时ViewModel在View ...

后面的代码中设置
public MainView()
{
    InitializeComponent();

    var viewModel = SimpleIoc.Default.GetInstance<MainViewModel>();
    DataContext = viewModel;
    Loaded += (s, e) => viewModel.LoadData();
}

View的Loaded事件设置为在显示View后调用ViewModel的LoadData()方法来触发数据加载。如果LoadData()很慢,可以将其更改为异步方法以防止UI阻塞。

对于那些抱怨这是一个过于紧密耦合的构造的人,我的观点是他们应该是这样的。尽管View和ViewModel是独立的实体,但每个View确切地知道它需要什么类型的ViewModel,并且这不太可能在项目开发生命周期中发生变化。在我看来,使用Locator类型类隐藏ViewModel构造函数调用是不必要的抽象级别。

答案 3 :(得分:-1)

要将视图与视图模型分离,其他东西需要实例化视图模型并管理其生命周期和共享。该工作可能属于IoC容器或简单的手动依赖注入。这完全取决于你。

E.g。来自Paul Stovell's article

public CalculatorView(CalculatorViewModel viewModel)
{
    InitializeComponent();
    DataContext = viewModel;
}

这一切都取决于你是通过脱钩来实现的。一个原因可能是您可以在同一个视图模型上拥有多个视图 - 在这种情况下,无论创建视图还需要创建视图模型。

另一个可能是将现有视图的视图模型与另一个视图模型交换而不破坏视图。在这种情况下,您可能已经拥有两个现有的视图模型,并根据需要将它们分配给视图DataContext

view.DataContext = viewModels[0];
view.DataContext = viewModels[1];