如何在初始化期间访问UserControl的XAML设置属性?
我们正在编写自定义UserControl(而不是无形控件),我们需要根据消费者在XAML中控制的属性执行一些初始化。
现在在大多数情况下,您使用Initialized事件(或OnInitialized覆盖),因为在触发时,已应用所有XAML集属性,但在UserControl的情况下,情况并非如此。 触发Initialized事件时,所有属性仍处于默认值。
我没有注意到其他控件,只是UserControls,它们在构造函数中调用InitializeComponent()是不同的,所以作为测试,我注释掉了行并运行代码,果然,这次是在Initialized期间事件,属性设置。
以下是一些代码和测试结果,certificate了这一点……
在构造函数中调用InitializeComponent的结果:
(注意:值仍未设置)
TestValue (Pre-OnInitialized): Original Value TestValue (Initialized Event): Original Value TestValue (Post-OnInitialized): Original Value
InitializeComponent的结果已完全注释掉:
(注意:虽然已设置值,但未加载控件,因为它需要InitializeComponent)
TestValue (Pre-OnInitialized): New Value! TestValue (Initialized Event): New Value! TestValue (Post-OnInitialized): New Value! // Event *was* called and the property has been changed
所有这些说,我可以使用什么来初始化我的控件基于XAML中的用户设置属性? (注意:加载已经太晚了,因为到那时控件应该已经初始化了。)
XAML片段
TestControl.cs
public partial class TestControl : UserControl { public TestControl() { this.Initialized += TestControl_Initialized; InitializeComponent(); } protected override void OnInitialized(EventArgs e) { Console.WriteLine("TestValue (Pre-OnInitialized): " + TestValue); base.OnInitialized(e); Console.WriteLine("TestValue (Post-OnInitialized): " + TestValue); } void TestControl_Initialized(object sender, EventArgs e) { Console.WriteLine("TestValue (Initialized Event): " + TestValue); } 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); } } }
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
之间调用这样的基于名称的初始化,事情会起作用正好。
请在调用InitializeComponent之前注册初始化事件。 每当调用EndInit或OnVisualParentChanges方法时,即在InitializeComponent之后,将引发此事件。
public TestControl() { this.Initialized += TestControl_Initialized; InitializeComponent(); }
谢谢