在WPF CAL MVVM中初始化模型和视图的正确方法是什么

在WPF CAL MVVM中初始化模型和视图的正确方法是什么,wpf,mvvm,unity-container,viewmodel,prism,Wpf,Mvvm,Unity Container,Viewmodel,Prism,我已经了解了在WPF CAL MVVM中初始化视图和视图模型的两种方法 1-似乎更受欢迎。要求您解析ViewModel以自动解析视图。ViewModel包含有关视图的信息 public interface IView { void SetModel(IViewModel model); } public interface IViewModel { IView View { get; } } public

我已经了解了在WPF CAL MVVM中初始化视图和视图模型的两种方法

1-似乎更受欢迎。要求您解析ViewModel以自动解析视图。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中删除视图。要求您解析视图以自动解析ViewModel。将对象注入视图(不确定这是否正确)

公共接口IView
{
}
公共接口IViewModel
{
}
公共阶级观
{
私有IViewModel模型;
公共视图(IUnityContainer unityContainer)
{
this.model=unityContainer.Resolve();
this.DataContext=this.model;
}
}
公共类视图模型
{
}

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

选项1看起来大致正确,为视图提供对viewmodel的引用

但是,让viewmodels引用视图对我来说似乎有点可疑。这看起来更像模型视图演示者类型的体系结构。如果您有与视图交互频繁的viewmodels,并且需要对视图的引用,那么最好将viewmodel拆分为纯粹用于数据绑定的viewmodel和执行更复杂交互的presenter


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

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

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

    ...

</UserControl>

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

    ...
}

...
公共部分类MyView:UserControl,IMyView
{
公共MyViewModel视图模型
{
获取{将this.DataContext作为MyViewModel返回;}
}
...
}
它们都是有效的,但#1往往更易于测试(它至少使您的测试更简洁)。#2的优点是它更明确,维护更清晰,特别是当你有大量的营业额时,诸如此类的事情。不需要太多解释(虽然这不是采用它的理由,但这只是一个真理)

区别在于,#1称为依赖注入#2称为服务位置。它们经常会被混淆,因为它们通常都使用某种IoC容器(尽管情况并非如此)


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

此代码的问题在于选项2的烘焙量超出了它需要的量。它真的不需要也不应该引用容器

另一种方法允许选项2与选项1一样可测试,但概念上更清晰,因为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; }
    }
如果希望使用xml文件指定布局,而不是使用棱柱区域(允许轻松配置布局),这将非常有用

备选方案:

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
{
}
在其他地方,你有:

Container.RegisterType<IViewModel, ViewModel>( /* appropriate container config */ );
Container.RegisterType<IView, View>(/* appropriate container config */ );
Container.RegisterType(/*适当的容器配置*/);
RegisterType(/*适当的容器配置*/);
您可以在任何地方使用以下工具创建视图:

Container.Resolve<IViewModel>();
Container.Resolve();

我在各种示例中发现了选项1中的视图属性,但我同意不应该存在该属性。+1注意类型分辨率不是视图的工作。我也使用这种方法,并且喜欢它。