5

我遇到了两种在 WPF CAL MVVM 中初始化视图和视图模型的方法。

1 - 似乎更受欢迎。要求您解析 ViewModel 以自动解析 View。ViewModel 包含有关视图的信息。

    public interface IView
    {
        void SetModel(IViewModel model);
    }

    public interface IViewModel
    {
        IView View { get; }
    }

    public class View
    {
        public void SetModel(IViewModel model)
        {
            this.DataContext = model;
        }
    }

    public class ViewModel
    {
        private IView view;

        public ViewModel(IView view)
        {
            this.view = view;
        }

        public IView View { return this.view; }
    }

2 - 看起来更干净,并从 ViewModel 中删除了 View。要求您解析 View 以自动解析 ViewModel。将对象注入视图(不确定这是否好)。

    public interface IView
    {
    }

    public interface IViewModel
    {
    }

    public class View
    {
        private IViewModel model;

        public View(IUnityContainer unityContainer)
        {
            this.model = unityContainer.Resolve<IViewModel>();
            this.DataContext = this.model;
        }
    }

    public class ViewModel
    {
    }

初始化视图和模型的公认方法是什么,每种方法的优缺点是什么。您应该将对象注入您的视图吗?

4

4 回答 4

3

它们都是有效的,但 #1 往往更易于测试(它至少使您的测试更简洁)。#2的优点是它往往更明确并且使维护更加清晰,尤其是当您有很多营业额时,诸如此类。需要较少的解释(尽管这不是采用它的理由,这只是一个不言而喻)。

不同之处在于#1 称为 Dependency Injection,而#2 称为 Service Location。他们经常感到困惑,因为他们通常都使用某种 IoC 容器(尽管不一定是这种情况)。

这最终是一个偏好问题,但正如我所说,我认为你会发现#1 更容易测试......你不必在测试/模拟中涉及 IUnityContainer 接口。

于 2010-01-16T15:58:41.477 回答
2

选项 1 看起来差不多,给视图一个对视图模型的引用。

不过,让视图模型引用回视图对我来说似乎有点可疑。这看起来更像是模型-视图-演示者类型的架构。如果您有与视图进行大量交互的视图模型并且需要对此视图的引用,那么您最好将视图模型拆分为纯粹用于数据绑定的视图模型和执行更复杂交互的演示者。

选项 2 看起来根本不对。在我的书中,将对 ioc 容器的引用传递给类是一种很大的代码味道。应尽量减少对 IoC 容器的调用。在我的大多数应用程序中,我只在程序开始时调用容器来连接东西。更动态的对象创建通常使用工厂类完成。

于 2010-01-15T15:43:33.877 回答
2

我更喜欢在 XAML 中定义视图模型并为类型化访问提供只读属性:

<UserControl ...>
    <UserControl.DataContext>
        <local:MyViewModel/>
    </UserControl.DataContext>

    ...

</UserControl>

public partial class MyView : UserControl, IMyView
{
    public MyViewModel ViewModel
    {
        get { return this.DataContext as MyViewModel; }
    }

    ...
}
于 2010-01-15T16:58:55.820 回答
1

The problem with this code is that option 2 is baking in more than it needs to. It really doesn't need and shouldn't have a reference to the container.

An alternative allows option 2 to be as testable as option 1, but conceptually clearer in that the ViewModel never knows about the View.

This is particularly useful if you want to specify your layout using an xml file as opposed to using the prism regions, which allows you to make the layout easily configurable.

Alternative:

public interface IView
{
}

public interface IViewModel
{
}

public class View : IView
{
    private IViewModel model;

    public View(IViewModel m)
    {
        this.model = m;
        this.DataContext = this.model;
    }
}

public class ViewModel : IViewModel
{
}

and somewhere else you have:

Container.RegisterType<IViewModel, ViewModel>( /* appropriate container config */ );
Container.RegisterType<IView, View>(/* appropriate container config */ );

and you could create a view anywhere with:

Container.Resolve<IViewModel>();
于 2011-07-21T03:29:03.507 回答