繁体   English   中英

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

[英]Specifically for a User Control, is there a place after the constructor, but before the Loaded event where you can access properties set in XAML?

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

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

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

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

思考?

更新

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

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

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

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

Awesomesausage! 我想到了!

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

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

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

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

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

是的! 那很有效! :)

这样你不仅拥有XAML集属性,而且在任何人获得Initialized事件(更不用说Loaded事件)之前你也会完全加载UI,这就是应该使用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); }
    }

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

Window.Initialized事件是在调用构造函数之后和Window.Loaded事件之前发生的。 然后将设置属性,但DynamicResourceBinding值不会。 从MSDN网站上的对象生命周期事件页面:

首先引发Initialized,并通过调用其构造函数粗略地对应于对象的初始化。 因为事件是在响应初始化时发生的,所以可以保证设置了对象的所有属性。 (一个例外是表达用法,例如动态资源或绑定;这些将是未评估的表达式。)由于要求设置所有属性,标记中定义的嵌套元素引发的Initialized序列似乎发生在首先是元素树中最深元素的顺序,然后是父元素朝向根。 此顺序是因为父子关系和包含是属性,因此父级无法报告初始化,直到填充属性的子元素也已完全初始化。

在编写处理程序以响应Initialized事件时,必须考虑到无法保证已创建元素树(逻辑树或可视树)中所有其他元素(包括处理程序附加的位置),尤其是父元素。 成员变量可能为null,或者数据源可能尚未由底层绑定填充(即使在表达式级别)。

一个8个月大的帖子在2天前得到了解答我遇到的确切问题(但是使用的是WinRT XAML,而不是WPF)。

使用包含Image控件的UserControl进入同样的问题。 UserControl具有自定义整数依赖项属性,其更改处理程序将Image.Source设置为新的BitmapImage(整数值确定要显示的图像)。

有一个竞争条件,图像并不总是正确显示。 很间歇,不幸的是我发布了一个带有bug的Win 8.1和WinPhone 8.1应用程序。 啊。

感谢您对MarqueIV和Sheridanless的贡献。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM