特别是对于用户控件,是否在构造函数之后有一个位置,但在Loaded事件之前,您可以访问在XAML中设置的属性?

Mar*_*eIV 8 c# wpf loaded

我们遇到一个问题,我们的用户控件是根据用户在使用我们的控件时在XAML中设置的内容进行初始化的.目前我们使用'Loaded'事件来对用户设置或未设置的内容采取行动.

但是,使用Loaded事件的另一个问题是这个控件的另一个兄弟是使用它们加载的事件来设置我们的东西,由于我们的 Loaded事件尚未触发,因此尚未完全初始化.(如果你愿意的话,这是一个UI竞争条件.)

同样,我们无法将代码移动到构造函数,因为WPF系统尚未设置我们控件的使用者的XAML指定的属性.出于上述原因,我们无法使用Loaded事件.初始化似乎也不起作用.

我也研究了ISupportsInitialize,但这就是我们批量设置控件属性的地方,而不是外部的东西,所以这似乎也不合适.

思考?

更新

我发现这是一个异常的UserControls异常.它们以不同的方式处理 您可以在我的后续问题中找到更多详细信息......

...但是短版本在构造函数中调用InitializeComponent实际上引发了Initialized事件,但是在实际设置了XAML定义的属性之前这样做了.注释掉它,现在在Initialized触发时设置属性,但当然你的控件的UI没有被加载!实际上有点令人沮丧.

仍在寻找解决方案.可以在那里找到代码示例和更多详细信息.

Mar*_*eIV 7

[ 在这里从我的其他问题复制我的答案.]

Awesomesausage!我想到了!

通常,当您收到Initialized事件(或在OnInitialized覆盖内)时,您可以访问XAML设置的属性值.但是,UserControl类的工作方式略有不同,因为它们依赖于InitializeComponent调用UI以及设置相关的成员变量等.

问题是调用是在构造函数中,而构造函数最终会调用OnInitialized(从而引发Initialized事件)但是在应用XAML集属性之前发生了这种情况,这意味着你还没有访问它们,这就是我需要.

有人可能认为这对Loaded事件很有用- 根据这些属性完成初始化 - 但是如果你在那里进行额外的初始化,那么如果他们订阅了你的Loaded事件,你就会与你的消费者创造潜在的竞争条件然后在你的处理程序中尝试访问你的控件,他们将访问一个未初始化的控件.

然后我发生了一些事情......正如我在上面所示,如果你InitializeComponent从构造函数中删除了调用,那么Initialized事件现在可以正常运行,但是当然你的UI还没有被充实,因为你尚未调用InitializeComponent.

那么,如果您在调用OnInitialized之前将该调用移动到覆盖的开头base.OnInitialized,并且因此在Initialized事件被引发之前,会发生什么?

是的!那很有效!:)

这样,您不仅可以拥有XAML设置属性,而且还可以在任何人获取Initialized事件之前完全加载UI (更不用说Loaded事件了),这就是Initialized事件应该如何使用的方式.

以下是修订后的代码......

public partial class TestControl : UserControl
{
    protected override void OnInitialized(EventArgs e)
    {
        InitializeComponent();
        base.OnInitialized(e);
    }

    public static readonly DependencyProperty TestValueProperty = DependencyProperty.Register(
        "TestValue",
        typeof(string),
        typeof(TestControl),
        new UIPropertyMetadata("Original Value"));

    public string TestValue
    {
        get { return (string)GetValue(TestValueProperty); }
        set { SetValue(TestValueProperty, value); }
    }

}
Run Code Online (Sandbox Code Playgroud)
  • 注意:除非您特别需要在那里做其他事情,否则不再需要构造函数.如果你这样做,只记得在InitializeComponent调用之前你不能按名称访问组成控件,但这只是意味着你必须计划在InitializeComponent这个调用之间移动这种基于名称的初始化,base.OnInitialize并且事情会正常工作.