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

发布于 2024-08-18 04:25:06 字数 1191 浏览 2 评论 0原文

我遇到过两种在 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
    {
    }

可接受的初始化视图和模型的方法是什么,每种方法的优点和缺点是什么。你应该将对象注入到你的视图中吗?

I have come accross two ways of initializing Views and ViewModels in WPF CAL MVVM.

1 - Seems to be more popular. Requires you to resolve the ViewModel to automatically resolve the View. The ViewModel contains information about the View.

    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 - Seems a lot cleaner and removes the View from the ViewModel. Requires you to resolve the View to automatically resolve the ViewModel. Injects objects into the view (Not sure if this is good or not).

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

What is the accepted method of initializing the views and models and what are the advantages and disadvantages of each method. Should you be injecting objects into your view?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

人疚 2024-08-25 04:25:06

它们都是有效的,但#1 往往更易于测试(它至少使您的测试更加简洁)。 #2 的优点是它往往更明确,并使维护更清晰,特别是当你有大量人员流动时,诸如此类的事情。不需要太多解释(尽管这不是采用它的理由,但这只是一个不言而喻的道理)。

不同之处在于,#1 称为依赖注入#2 称为服务位置。它们经常被混淆,因为它们通常都使用某种 IoC 容器(尽管情况不一定如此)。

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

They are both valid, but #1 tends to be more testable (it at least makes your tests more concise). The advantage to #2 is that it tends to be more explicit and makes maintenance a little more clear, especially when you have a lot of turnover, that kind of thing. Takes less explaining (though this is not a reason to adopt it, it's just a truism).

The difference is that #1 is called Dependency Injection and #2 is called Service Location. They are often confused because they both generally utilize some sort of IoC container (although this doesn't have to be the case).

It's a matter of preference in the end, but as I said I think you will find #1 a lot easier to test... you won't have to involve the IUnityContainer interface in your testing / mocking.

殤城〤 2024-08-25 04:25:06

选项 1 看起来差不多是正确的,为视图提供对视图模型的引用。

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

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

Option 1 looks about right, give the view a reference to the viewmodel.

Having viewmodels with a reference back to the view seems a bit fishy to me though. That looks more like a model-view-presenter type architecture. If you've got viewmodels that interact heavilly with the view and need a reference to the view for that you might be better off splitting the viewmodel in a viewmodel used purely for databinding and a presenter that does more complex interaction.

Option 2 doesn't look right at all. Passing a reference to the ioc container into classes is a big code smell in my book. Calls to an IoC container should be minimized. In most of my applications I only call into the container at the start of the program to wire stuff up. More dynamic object creation is usually done with factory classes.

ˉ厌 2024-08-25 04:25:06

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

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

    ...

</UserControl>

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

    ...
}

I prefer to define the view model in XAML and provide a read-only property for typed access:

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

    ...

</UserControl>

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

    ...
}
无妨# 2024-08-25 04:25:06

这段代码的问题是选项 2 的烘焙量超出了它的需要。它确实不需要也​​不应该引用容器。

另一种选择允许选项 2 与选项 1 一样可测试,但概念上更清晰,因为 ViewModel 永远不知道 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.Resolve<IViewModel>();

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>();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文