避免 Prism AutoWireViewModel 创建 ViewModel 两次 [英] Avoid Prism AutoWireViewModel Creating the ViewModel Twice

查看:127
本文介绍了避免 Prism AutoWireViewModel 创建 ViewModel 两次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果您的视图上有一个单参数构造函数,Prism 可以创建一个不需要的 ViewModel.我试图了解如何避免这种情况,或者,如果我可以设计出不同的工作方式.这是发生的事情.

Prism can create an unneeded ViewModel if you have a one-arg constructor on your view. I am trying to understand how this can be avoided, or, if I can design something to work differently. Here is what happens.

XAML 视图声明 ViewModelLocator.AutoWireViewModel:

The XAML view declares ViewModelLocator.AutoWireViewModel:

mvvm:ViewModelLocator.AutoWireViewModel="True"

并且该类声明了两个构造函数:

And the class declares two constructors:

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

    public MainWindow(MainWindowViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }
}

我声明单参数构造函数是有原因的:因为ViewModel是可序列化的;当反序列化时,视图是通过使用恢复的 ViewModel 显式调用该构造函数来构造的.但是这个问题可以通过两种方式发生.

There is a reason that I declare the one-arg constructor: it is because the ViewModel is serializable; and when deserialized, the view is constructed by explicitly invoking that constructor with the restored ViewModel. But the issue can happen in two ways.

首先,当您调用单参数构造函数时:

First, when you invoke the one-arg constructor:

MainWindowViewModel viewModel = new MainWindowViewModel();
MainWindow window = new MainWindow(viewModel);

然后 Prism 构造视图,并从 XAML 调用 ViewModelLocator,它创建并设置一个 ViewModel ......然后你的显式参数被设置;替换自动创建的实例(或者如果您反转构造函数中的行,那么您的显式参数实际上会被删除).

Then Prism constructs the view, and that invokes the ViewModelLocator from the XAML, which creates and sets a ViewModel ... And then your explicit argument is set; replacing the auto-created instance (or if you reverse the lines in the constructor, than your explicit argument is actually wiped off).

并且,也许是出乎意料的,也许是我理解的一些愚蠢,或其他一些未知的设计方面,如果您从 Container 解析视图,它也会发生——您可能会这样做,希望为它调用默认构造函数风景;但事实上并没有发生;并且,您将再次创建两个 ViewModel:

AND, perhaps unexpectedly, or perhaps by some folly in my understanding, or some other unknown design aspect, it ALSO will happen if you resolve the view from the Container --- you might do this expecting to invoke the default constructor for the view; but that in fact does not happen; and, once again you will create two ViewModels:

MainWindow window = Container.Resolve<MainWindow>();

这行代码实际上是从发现 View 上的单参数构造函数开始的,然后解析一个 ViewModel 并调用该构造函数......这再次触发 XAML 自动 ViewModel;然后你的单参数构造函数继续擦除自动 ViewModel ...

This line of code actually begins by discovering the one-arg constructor on the View, and then RESOLVING a ViewModel and invoking that constructor ... which again triggers the XAML auto-ViewModel; and then your one-arg constructor continues to wipe off the auto-ViewModel ...

正在消耗资源;事实上,我遇到了一个异常,其中视图绑定基于与我期望显式设置的 ViewModel 不一致的其他一些状态.

It's consuming resources; and in fact, I tripped an exception where the view was binding based on some other state that was inconsistent with the ViewModel that I was expecting to explicitly be set.

我看不到打败自动创建的实例的方法,所以我没有看到如何围绕 AutoWireViewModel 行为调用单参数构造函数;或者,如何从 Container 解析视图并避免创建两个 ViewModel.

I can't see a way to defeat the auto-created instance, and so I am not seeing how to invoke a one-arg constructor around the AutoWireViewModel behavior; or, how to resolve the view from the Container and avoid two ViewModels being created.

如果没有注册的话,从Container解析View可能是滥用,但是one-arg构造函数似乎是合理的,并且它创建了两个实例......

Perhaps resolving the View from the Container is abuse if it hasn't been registered, but the one-arg constructor seems to be reasonable, and it creates two instances ...

有什么办法吗?[也许您可以自定义该行为以检查现有的 DataContext,然后不设置它(如果存在)......或类似的东西?]

Is there some way? [Perhaps you can customize that behavior to check for an existing DataContext and then not set it if present ... or something along those lines?]

我在 GitHub 上创建了一个简单的示例:

I created a simple example on GitHub:

https://github.com/steevcoco/PrismAutoCreatesViewModelTwice

推荐答案

好吧,就其价值而言,我实际上已经实现了一个自定义 ViewModelLocator 来解决此行为.它有点粗糙:它只是首先检查当前的 DataContext 是否为非空;如果是这样,AutoWire 将不会创建或设置 Viewmodel.

Well, for what it's worth, I have actually implemented a custom ViewModelLocator that works around this behavior. It is somewhat crude: it simply first checks if the current DataContext is non-null; and if so, the AutoWire will not create or set a Viewmodel.

我已经为感兴趣的人更新了代码库中的代码.

I have updated the code in the repository for anyone interested.

这篇关于避免 Prism AutoWireViewModel 创建 ViewModel 两次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆