在初始化期间,如何访问UserControl的XAML设置属性? [英] How can you access XAML-set properties of a UserControl during initialization?

查看:87
本文介绍了在初始化期间,如何访问UserControl的XAML设置属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在编写一个自定义UserControl(而不是一个无外观的控件),并且需要根据使用者在XAML中的控件上设置的属性来执行一些初始化.

We're writing a custom UserControl (as opposed to a lookless control) and we need to perform some initialization based on what properties our consumers set on our control in XAML.

现在,在大多数情况下,您将使用Initialized事件(或OnInitialized覆盖),因为在触发时,所有XAML设置的属性均已应用,但对于UserControl,则不是案子.初始化事件触发时,所有属性仍为默认值.

Now in most cases, you'd use the Initialized event (or the OnInitialized override) since by the time that fires, all the XAML-set properties have been applied, but in the case of a UserControl, that isn't the case. When the Initialized event fires, all properties are still at their default values.

对于其他控件,我没有注意到,只是UserControls,它们的不同之处在于它们在构造函数中调用了InitializeComponent(),因此作为测试,我注释了这一行并运行了代码,这次确定了在初始化事件期间,设置了 属性.

I didn't notice this for other controls, just UserControls, which are different in that they call InitializeComponent() in their constructor, so as a test, I commented that line out and ran the code and sure enough, this time during the Initialized event, the properties were set.

这里有一些代码和测试结果证明了这一点...

Here is some code and test results demonstrating this...

在构造函数中调用了InitializeComponent的结果:
(注意:这些值仍未设置)

Result with InitializeComponent called in the constructor:
(Note: The values still have not been set)

TestValue (Pre-OnInitialized): Original Value
TestValue (Initialized Event): Original Value
TestValue (Post-OnInitialized): Original Value

带有InitializeComponent的结果已完全注释掉:
(注意:设置了值后,由于需要InitializeComponent,因此未加载控件)

Result with InitializeComponent completely commented out:
(Note: While the values have been set, the control isn't loaded as it needs 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中的用户设置属性来初始化控件吗? (注意:加载已太迟,因为届时控件应该已经初始化了.)

All this said, what can I use to initialize my control based on user-set properties in the XAML? (Note: Loaded is too late as the control should already have been initialized by then.)

XAML代码段

<local:TestControl TestValue="New Value!" />

TestControl.cs

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! I figured it out!

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

Normally when you receive the Initialized event (or are inside the OnInitialized override) you have access to XAML-set property values. However, UserControl classes work a little differently as they depend on InitializeComponent being called to hydrate the UI and set the related member variables, etc.

问题在于调用在构造函数中,该构造函数最终导致调用OnInitialized(并因此引发了Initialized事件),但这是在应用XAML设置属性之前发生的,这意味着您没有还没有我需要的权限.

The problem is that call is in the constructor, which in turn ends up calling OnInitialized (and thus raising the Initialized event) but that happens way before the XAML-set properties have been applied, meaning you don’t have access to them yet, which I needed.

有人可能认为Loaded事件是一个很好的用途-根据这些属性完成初始化-但是,如果您在此处执行其他初始化,则可能会与消费者建立潜在的竞争条件如果他们订阅了您的Loaded事件并在您之前获取了它,则在其处理程序中尝试访问您的控件,他们将访问一个未初始化的控件.

One may think that's a good use for the Loaded event--to finish initialization based on those properties--but if you're performing additional initialization there, you're creating a potential race condition with your consumers in that if they subscribe to your Loaded event and get it before you, then in their handler try to access your control, they will be accessing an uninitialized control.

然后我发生了一些事情...如上所示,如果您从构造函数中删除了InitializeComponent调用,则Initialized事件现在可以按您期望的方式工作,但是您的UI当然还没有水化因为您尚未致电InitializeComponent.

Then something occurred to me... As I showed above, if you remove the InitializeComponent call from the constructor, the Initialized event now works as you would expect, but of course your UI isn't hydrated yet since you haven't yet called InitializeComponent.

那么,如果您将该调用移到OnInitialized替代的开头,在调用base.OnInitialized之前,因此在引发Initialized事件之前,会发生什么情况?

So what would happen if you moved that call to the beginning of the OnInitialized override, before the call to base.OnInitialized, and thus before the Initialized event was raised?

是的!奏效了! :)

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

This way not only do you have the XAML-set properties, but you’d also have the UI fully loaded before anyone gets the Initialized event (let alone the Loaded event), which is how the Initialized event is supposed to be used.

下面是修改后的代码...

Below is the revised code...

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与该调用之间移动此类基于名称的初始化.一切都会好起来的.
    • Note: You don't need the constructor anymore unless you have a specific need to do other things there. And if you do, just remember you can't access constituent controls by name until after the InitializeComponent call, but that just means you have to plan to move such name-based initialization between InitializeComponent and that call to base.OnInitialize and things will work just fine.
    • 这篇关于在初始化期间,如何访问UserControl的XAML设置属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆