我们正在编写一个自定义UserControl(而不是一个无外观的控件),并且需要根据使用者在XAML中的控件上设置的属性来执行一些初始化。
现在,在大多数情况下,您将使用Initialized事件(或OnInitialized覆盖),因为在触发时,所有XAML设置的属性均已应用,但对于UserControl,情况并非如此。当初始化事件触发时,所有属性仍为默认值。
我没有注意到其他控件,只是UserControl,它们的不同之处在于它们在其构造函数中调用了InitializeComponent(),因此作为测试,我注释了这一行并运行了代码,这是确定的,这次是在Initialized中事件,设置属性。
这是一些代码和测试结果证明了这一点...
在构造函数中调用了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代码段
<local:TestControl TestValue="New Value!" />
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); }
}
}
最佳答案
很棒的香肠!我想到了!
通常,当您收到Initialized
事件(或在OnInitialized
覆盖内)时,您可以访问XAML设置的属性值。但是,UserControl
类的工作方式略有不同,因为它们依赖于调用InitializeComponent
来水合UI并设置相关的成员变量等。
问题在于调用是在构造函数中进行的,而该构造函数最终会调用OnInitialized
(从而引发Initialized
事件),但这是在应用XAML-set属性之前发生的,这意味着您尚无权访问它们,我需要的。
可能有人认为Loaded
事件是一种很好的用法-根据这些属性完成初始化-但如果您在此处执行其他初始化,则可能会与消费者产生潜在的竞争条件,因为如果消费者订阅了您的Loaded
事件并在您之前获取它,然后在其处理程序中尝试访问您的控件,他们将访问未初始化的控件。
然后发生了一些事情……如上所示,如果您从构造函数中删除了InitializeComponent
调用,则Initialized
事件现在可以按您期望的那样工作了,但是您的UI当然还没有水化,因为您尚未调用InitializeComponent
。
那么,如果将调用移到OnInitialized
覆盖的开头,调用base.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
的调用将正常进行。 关于c# - 在初始化期间,如何访问UserControl的XAML设置属性?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/18583196/