C# 初始化期间如何访问UserControl的XAML集属性?

C# 初始化期间如何访问UserControl的XAML集属性?,c#,wpf,user-controls,initialization,C#,Wpf,User Controls,Initialization,我们正在编写一个自定义用户控件(与无外观控件相反),并且需要根据使用者在XAML中对控件设置的属性执行一些初始化 现在,在大多数情况下,您都会使用初始化事件(或OnInitialized重写),因为在触发时,所有XAML集合属性都已应用,但对于UserControl,情况并非如此。当初始化事件激发时,所有属性仍处于其默认值 对于其他控件,我没有注意到这一点,只是UserControls,它们的不同之处在于它们在构造函数中调用InitializeComponent(),因此作为一个测试,我对该行进

我们正在编写一个自定义用户控件(与无外观控件相反),并且需要根据使用者在XAML中对控件设置的属性执行一些初始化

现在,在大多数情况下,您都会使用初始化事件(或OnInitialized重写),因为在触发时,所有XAML集合属性都已应用,但对于UserControl,情况并非如此。当初始化事件激发时,所有属性仍处于其默认值

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

下面是一些代码和测试结果,演示了这一点

构造函数中调用InitializeComponent的结果:
(注意:尚未设置值)

InitializeComponent被完全注释掉的结果:
(注意:虽然已设置值,但由于控件需要InitializeComponent,因此未加载该控件)

综上所述,基于XAML中的用户集属性,我可以使用什么来初始化我的控件?(注意:加载太晚,因为此时控件应该已经初始化。)

XAML片段

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

请在调用InitializeComponent之前注册初始化事件。每当调用EndInit或OnVisualParentChanges方法时,即在InitializeComponent之后,都会引发此事件

  public TestControl()
    {

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

谢谢

太棒了!我知道了

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

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

有人可能认为加载的
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之间移动基于名称的初始化。只需初始化
    ,一切都会正常工作

不太好!我刚刚更新了我的问题,表明当我发现InitializeComponent引发了那个事件时。问题是XAML集合属性在那时还没有设置。请参阅上面的新输出。为什么不使用加载的事件?属性值将在那个时候设置。正如我前面所说的,由于各种其他原因,加载太迟了。我们的控件应该在触发时被完全构造,如果其他侦听我们加载的事件的东西在我们之前得到它,那么我们就不同步了。不过,我认为我找到了一个似乎有效的解决方案。见上文…在类似情况下为我工作。谢谢你的发现!很高兴我能帮忙。当我意识到这一点时,这是一个快乐的时刻。
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); }
    }

}
  public TestControl()
    {

        this.Initialized += TestControl_Initialized;
        InitializeComponent();
    }
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); }
    }

}