如果在构造函数中设置DataContext,那么在调用InitializeComponent()之前或之后设置它是否重要?

我有一个WPF窗口,在它的构造函数中有一些参数。 然后我使用这些构造函数来设置窗口的状态。 该构造函数进程的一部分是实例化我的视图模型类,然后将其设置为windows DataContext

我的问题是,在调用InitializeComponent()之前或之后,我应该何时将DataContext设置为等于我的视图模型对象?

我问,因为如果我事先设置它,那么我需要手动启动窗口初始化执行的代码,因为某些事件应该在分配或重新分配DataContext时触发。

如果我在调用InitializeComponent()之后设置DataContext ,那么我的假设不应该存在任何绑定问题,但我想在最后调用以这种方式连接我的窗口之前询问有关此问题的建议。 如果在调用InitializeComponent()之后设置DataContext ,我可能会遗漏一些可能会回来困扰我的东西吗?

我的问题是,在调用InitializeComponent()之前或之后,我应该何时将DataContext设置为等于我的视图模型对象?

除非您依赖于在调用InitializeComponent()期间建立的某些绑定(如ElementName绑定),否则无关紧要:

无法将ItemsSource绑定到ElementName

InitializeComponent()方法本身将URI定位到已编译的XAML文件,并将其传递给解析BAML的LoadComponent()方法,即已编译的XAML,并创建您在XAML标记中定义的元素的实例:

.xaml和.xaml.cs文件之间的连接是什么

简单地将窗口的DataContext属性设置为视图模型类的实例,视图中的元素也可以在调用InitializeComponent()方法之后完成。 无论如何,在构造函数返回之前,这些绑定都不会被解析。

与你的要求不同,我建议两个变化:

  1. 设置内部元素的DataContext而不是Window / UserControl本身。
  2. Loaded上设置DataContext而不是构造函数。

在查看可能嵌入多个点的UserControl ,这些点更加明显,但请记住,可以通过显式启动代码而不是某些App.StartupUri创建Window

关于第一点,请考虑OOP设计基础知识。 忘记WPF / XAML细节,并记住您从Window类派生并创建它的子类。 此类的合同包括一个名为DataContext的公共get / set属性,它接受任何类型的object 。 所以,如果有人从外部替换你的DataContext ,你至少应该考虑一下,有多糟糕。 当您在窗口内的下一个内部FrameworkElement上设置DataContext时,它将托管在窗口所拥有的环境中。

Loaded上设置DataContext对我Loaded ,而我在构造函数时间设置方面遇到了问题。 但是,我实际上无法回想起它的细节,也许它与视觉设计师(我不再使用)有关。 对于其他控件,更容易解释:构造函数时间初始化在虚拟化面板中托管时很糟糕,属性初始化器( new MyControl { Prop = Value } ,XAML属性赋值,…)也不会在构造函数运行时处理,所以对象倾向于处于与稍后呈现的状态不同的状态。

这是我对@ mm8答案的补充:

  1. 通常没关系,但在InitializeComponents之后设置DataContext。 调用DataContextChanged事件时,您自然希望组件已经初始化。

    另外,最好知道是否可以在没有DataContext的情况下初始化组件,并将可能的初始化问题与绑定问题分开。 如果在InitializeComponents之前设置DataContext,则绑定问题可能会导致InitializeComponents中出现exception。

  2. 使ViewModel构造函数非常快。 不要进行任何数据库调用或任何I / O调用等。您希望尽快显示UI。

  3. 确保您的ViewModel构造函数从不抛出exception。 参数validation没问题,但仅用于调试目的。 它绝不应该在生产中发生。

  4. 如果需要将数据加载到viewmodel中,请创建单独的异步方法,例如Activate() ,您将从View的LoadedOnNavigatedTo事件中调用它。

    此外,如果您订阅ViewModel中的某些事件,则应取消订阅。 订阅的理想场所是Activate方法,resp Deactivate订阅取消订阅。 如果您在ViewModel的ctor中订阅,可能会发生永远不会调用Activate / Deactivate并引入内存泄漏的情况。

  5. 如果您认为绑定会降低UI的速度,请尝试使用{Binding IsAsync=True} ,resp x:Bind ,或尝试使用codebehind在最坏的情况下设置属性。