簡體   English   中英

如何在初始化期間訪問UserControl的XAML設置屬性?

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

我們正在編寫自定義UserControl(而不是無形控件),我們需要根據消費者在XAML中控制的屬性執行一些初始化。

現在在大多數情況下,您將使用Initialized事件(或OnInitialized覆蓋),因為在觸發時,已應用了所有XAML集屬性,但在UserControl的情況下,情況並非如此。 觸發Initialized事件時,所有屬性仍處於默認值。

我沒有注意到其他控件,只是UserControls,不同之處在於它們在構造函數中調用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); }
    }

}

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

謝謝

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM