簡體   English   中英

特別是對於用戶控件,是否在構造函數之后有一個位置,但在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中設置的內容進行初始化的。 目前我們使用'Loaded'事件來對用戶設置或未設置的內容采取行動。

但是,使用Loaded事件的另一個問題是這個控件的另一個兄弟是使用它們加載的事件來設置我們的東西,因為我們的 Loaded事件尚未觸發,所以尚未完全初始化。 (如果你願意的話,這是一個UI競爭條件。)

同樣,我們無法將代碼移動到構造函數,因為WPF系統尚未設置我們控件的使用者的XAML指定的屬性。 出於上述原因,我們無法使用Loaded事件。 初始化似乎也不起作用。

我也研究了ISupportsInitialize,但這就是我們批量設置控件屬性的地方,而不是外部的東西,所以這似乎也不合適。

思考?

更新

我發現這是一個異常的UserControls異常。 它們以不同的方式處理 您可以在我的后續問題中找到更多詳細信息......

...但是短版本在構造函數中調用InitializeComponent實際上引發了Initialized事件,但是在實際設置了XAML定義的屬性之前這樣做了。 注釋掉它,現在在Initialized觸發時設置屬性,但當然你的控件的UI沒有被加載! 實際上有點令人沮喪。

仍在尋找解決方案。 可以在那里找到代碼示例和更多詳細信息。

[ 在這里從我的其他問題復制我的答案。]

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調用之間移動這種基於名稱的初始化,事情會起作用正好。

Window.Initialized事件是在調用構造函數之后和Window.Loaded事件之前發生的。 然后將設置屬性,但DynamicResourceBinding值不會。 從MSDN網站上的對象生命周期事件頁面:

首先引發Initialized,並通過調用其構造函數粗略地對應於對象的初始化。 因為事件是在響應初始化時發生的,所以可以保證設置了對象的所有屬性。 (一個例外是表達用法,例如動態資源或綁定;這些將是未評估的表達式。)由於要求設置所有屬性,標記中定義的嵌套元素引發的Initialized序列似乎發生在首先是元素樹中最深元素的順序,然后是父元素朝向根。 此順序是因為父子關系和包含是屬性,因此父級無法報告初始化,直到填充屬性的子元素也已完全初始化。

在編寫處理程序以響應Initialized事件時,必須考慮到無法保證已創建元素樹(邏輯樹或可視樹)中所有其他元素(包括處理程序附加的位置),尤其是父元素。 成員變量可能為null,或者數據源可能尚未由底層綁定填充(即使在表達式級別)。

一個8個月大的帖子在2天前得到了解答我遇到的確切問題(但是使用的是WinRT XAML,而不是WPF)。

使用包含Image控件的UserControl進入同樣的問題。 UserControl具有自定義整數依賴項屬性,其更改處理程序將Image.Source設置為新的BitmapImage(整數值確定要顯示的圖像)。

有一個競爭條件,圖像並不總是正確顯示。 很間歇,不幸的是我發布了一個帶有bug的Win 8.1和WinPhone 8.1應用程序。 啊。

感謝您對MarqueIV和Sheridanless的貢獻。

暫無
暫無

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

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