避免 Prism AutoWireViewModel 两次创建 ViewModel
Avoid Prism AutoWireViewModel Creating the ViewModel Twice
如果您的视图上有一个单参数构造函数,Prism 可以创建不需要的 ViewModel。我试图了解如何避免这种情况,或者,如果我可以设计一些不同的工作方式。事情是这样的。
XAML 视图声明 ViewModelLocator.AutoWireViewModel:
mvvm:ViewModelLocator.AutoWireViewModel="True"
并且 class 声明了两个构造函数:
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
public MainWindow(MainWindowViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
我声明单参数构造函数是有原因的:因为 ViewModel 是可序列化的;反序列化时,通过使用恢复的 ViewModel 显式调用该构造函数来构造视图。但是这个问题可以通过两种方式发生。
首先,当您调用单参数构造函数时:
MainWindowViewModel viewModel = new MainWindowViewModel();
MainWindow window = new MainWindow(viewModel);
然后 Prism 构建视图,并从 XAML 调用 ViewModelLocator,它创建并设置一个 ViewModel ...然后设置您的显式参数;替换自动创建的实例(或者如果你反转构造函数中的行,那么你的显式参数实际上被擦掉了)。
并且,也许是出乎意料的,或者可能是我理解中的一些愚蠢行为,或者是其他一些未知的设计方面,如果您从容器中解析视图,它也会发生——您可能会期望调用默认设置视图的构造函数;但实际上并没有发生;并且,您将再次创建两个 ViewModel:
MainWindow window = Container.Resolve<MainWindow>();
这行代码实际上是从发现 View 上的单参数构造函数开始的,然后解析 ViewModel 并调用该构造函数……这再次触发了 XAML auto-ViewModel;然后您的单参数构造函数继续擦除自动 ViewModel ...
正在消耗资源;事实上,我触发了一个异常,其中视图基于与我期望明确设置的 ViewModel 不一致的其他状态进行绑定。
我看不到击败自动创建实例的方法,因此我看不到如何围绕 AutoWireViewModel 行为调用单参数构造函数;或者,如何从容器解析视图并避免创建两个 ViewModel。
如果未注册,从容器解析视图可能是滥用,但单参数构造函数似乎是合理的,它创建了两个实例...
有什么办法吗? [也许您可以自定义该行为以检查现有的 DataContext,然后在存在时不设置它……或者类似的东西?]
我在 GitHub 上创建了一个简单示例:
好吧,尽管如此,我实际上已经实现了一个自定义 ViewModelLocator 来解决此问题。它有点粗糙:它只是首先检查当前 DataContext 是否为非空;如果是这样,AutoWire 将不会创建或设置 Viewmodel。
我已经为任何感兴趣的人更新了存储库中的代码。
这里要明确一点,Prism 并没有创建 ViewModel 两次。你是。你在后面的代码中用 ctor 做一次,然后用 ViewModelLocator 再做一次。选择一种方法并使用它。无需使用两种不同的方式在同一个视图上设置 VM。
您应该仔细阅读容器及其工作原理。这将有助于您了解这里发生的事情。一切都在正常工作。
如果您的视图上有一个单参数构造函数,Prism 可以创建不需要的 ViewModel。我试图了解如何避免这种情况,或者,如果我可以设计一些不同的工作方式。事情是这样的。
XAML 视图声明 ViewModelLocator.AutoWireViewModel:
mvvm:ViewModelLocator.AutoWireViewModel="True"
并且 class 声明了两个构造函数:
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
public MainWindow(MainWindowViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
}
我声明单参数构造函数是有原因的:因为 ViewModel 是可序列化的;反序列化时,通过使用恢复的 ViewModel 显式调用该构造函数来构造视图。但是这个问题可以通过两种方式发生。
首先,当您调用单参数构造函数时:
MainWindowViewModel viewModel = new MainWindowViewModel();
MainWindow window = new MainWindow(viewModel);
然后 Prism 构建视图,并从 XAML 调用 ViewModelLocator,它创建并设置一个 ViewModel ...然后设置您的显式参数;替换自动创建的实例(或者如果你反转构造函数中的行,那么你的显式参数实际上被擦掉了)。
并且,也许是出乎意料的,或者可能是我理解中的一些愚蠢行为,或者是其他一些未知的设计方面,如果您从容器中解析视图,它也会发生——您可能会期望调用默认设置视图的构造函数;但实际上并没有发生;并且,您将再次创建两个 ViewModel:
MainWindow window = Container.Resolve<MainWindow>();
这行代码实际上是从发现 View 上的单参数构造函数开始的,然后解析 ViewModel 并调用该构造函数……这再次触发了 XAML auto-ViewModel;然后您的单参数构造函数继续擦除自动 ViewModel ...
正在消耗资源;事实上,我触发了一个异常,其中视图基于与我期望明确设置的 ViewModel 不一致的其他状态进行绑定。
我看不到击败自动创建实例的方法,因此我看不到如何围绕 AutoWireViewModel 行为调用单参数构造函数;或者,如何从容器解析视图并避免创建两个 ViewModel。
如果未注册,从容器解析视图可能是滥用,但单参数构造函数似乎是合理的,它创建了两个实例...
有什么办法吗? [也许您可以自定义该行为以检查现有的 DataContext,然后在存在时不设置它……或者类似的东西?]
我在 GitHub 上创建了一个简单示例:
好吧,尽管如此,我实际上已经实现了一个自定义 ViewModelLocator 来解决此问题。它有点粗糙:它只是首先检查当前 DataContext 是否为非空;如果是这样,AutoWire 将不会创建或设置 Viewmodel。
我已经为任何感兴趣的人更新了存储库中的代码。
这里要明确一点,Prism 并没有创建 ViewModel 两次。你是。你在后面的代码中用 ctor 做一次,然后用 ViewModelLocator 再做一次。选择一种方法并使用它。无需使用两种不同的方式在同一个视图上设置 VM。
您应该仔细阅读容器及其工作原理。这将有助于您了解这里发生的事情。一切都在正常工作。