简体   繁体   English

如何在初始化期间访问UserControl的XAML设置属性?

[英]How can you access XAML-set properties of a UserControl during initialization?

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. 我们正在编写自定义UserControl(而不是无形控件),我们需要根据消费者在XAML中控制的属性执行一些初始化。

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. 现在在大多数情况下,您将使用Initialized事件(或OnInitialized覆盖),因为在触发时,已应用了所有XAML集属性,但在UserControl的情况下,情况并非如此。 When the Initialized event fires, all properties are still at their default values. 触发Initialized事件时,所有属性仍处于默认值。

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. 我没有注意到其他控件,只是UserControls,不同之处在于它们在构造函数中调用InitializeComponent(),所以作为测试,我评论说该行并运行代码,果然,这次是在Initialized期间事件的性质设定。

Here is some code and test results demonstrating this... 以下是一些代码和测试结果,证明了这一点......

Result with InitializeComponent called in the constructor: 在构造函数中调用InitializeComponent的结果:
(Note: The values still have not been set) (注意:值仍未设置)

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

Result with InitializeComponent completely commented out: InitializeComponent的结果已完全注释掉:
(Note: While the values have been set, the control isn't loaded as it needs 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

All this said, what can I use to initialize my control based on user-set properties in the XAML? 所有这些说,我可以使用什么来初始化我的控件基于XAML中的用户设置属性? (Note: Loaded is too late as the control should already have been initialized by then.) (注意:加载已经太晚了,因为到那时控件应该已经初始化了。)

XAML Snippet 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! Awesomesausage! I figured it out! 我想到了!

Normally when you receive the Initialized event (or are inside the OnInitialized override) you have access to XAML-set property values. 通常,当您收到Initialized事件(或在OnInitialized覆盖内)时,您可以访问XAML设置的属性值。 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. 但是, UserControl类的工作方式略有不同,因为它们依赖于调用InitializeComponent来水合UI并设置相关的成员变量等。

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

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

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

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

Yep! 是的! That worked! 那很有效! :) :)

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

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); }
    }

}
  • 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. 如果你这样做,只记得在InitializeComponent调用之前你不能按名称访问组成控件,但这只是意味着你必须计划在InitializeComponent和对base.OnInitialize调用之间移动这种基于名称的初始化,事情会起作用正好。

Please register the intialized event before calling InitializeComponent. 请在调用InitializeComponent之前注册初始化事件。 This event will be raised whenever the EndInit or OnVisualParentChanges methods are called ie after InitializeComponent. 只要调用EndInit或OnVisualParentChanges方法(即在InitializeComponent之后),就会引发此事件。

  public TestControl()
    {

        this.Initialized += TestControl_Initialized;
        InitializeComponent();
    }

Thanks 谢谢

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

相关问题 特别是对于用户控件,是否在构造函数之后有一个位置,但在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中设置用户控件的列表项 - How to Set List Items of a usercontrol in XAML 如何从另一个类访问userControl中的某些属性? - How can I access some properties in userControl from another class? 如何从XAML设置WPF usercontrol属性? - How to set a WPF usercontrol property from XAML? 您能否区分对象初始化期间的属性集和单独的属性集? - Can you differentiate between a property set during object initialization and one set separately? 是否可以重新加载UserControl的XAML属性? - Is it possible to reload XAML properties of a UserControl? 如何在C#中访问usercontrol的属性 - How to access properties of a usercontrol in C# 如何访问 C# 中 Inherited UserControl 中的属性? - How to access properties that are in an Inherited UserControl in C#? 如何在WinRt Xaml中访问UserControl的父资源 - How to access a UserControl's parent resources in WinRt Xaml 如何从xaml访问UserControl中的按钮? - How do I Access Buttons inside a UserControl from xaml?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM