相依性屬性值優先順序 (WPF .NET)

Windows Presentation Foundation (WPF) 屬性系統的工作會影響相依性屬性的值。 本文說明 WPF 屬性系統中不同屬性型輸入的優先順序如何決定相依性屬性的有效值。

重要

.NET 7 和 .NET 6 的桌面指南檔正在建置中。

必要條件

本文假設您具備相依性屬性的基本知識,而且您已閱讀 相依性屬性概觀 。 若要遵循本文中的範例,如果您熟悉可延伸的應用程式標記語言(XAML),並知道如何撰寫 WPF 應用程式,它很有説明。

WPF 屬性系統

WPF 屬性系統會使用各種因素來判斷相依性屬性的值,例如即時屬性驗證、晚期繫結,以及相關屬性的屬性變更通知。 雖然用來判斷相依性屬性值的順序和邏輯很複雜,但學習它可協助您避免不必要的屬性設定,並找出為何嘗試設定相依性屬性不會產生預期的值。

相依性屬性設定于多個位置

下列 XAML 範例顯示按鈕 Background 屬性上三個不同的「設定」作業如何影響其值。

<StackPanel>
    <StackPanel.Resources>
        <ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
            <Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" 
                    BorderBrush="{TemplateBinding BorderBrush}">
                <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
            </Border>
        </ControlTemplate>
    </StackPanel.Resources>

    <Button Template="{StaticResource ButtonTemplate}" Background="Red">
        <Button.Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Background" Value="Blue"/>
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Background" Value="Yellow" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Button.Style>
        Which color do you expect?
    </Button>
</StackPanel>

在此範例中, Background 屬性會在本機設定為 Red 。 不過,在按鈕範圍中宣告的隱含樣式會嘗試將 Background 屬性設定為 Blue 。 而且,當滑鼠停留在按鈕上方時,隱含樣式中的觸發程式會嘗試將 Background 屬性設定為 Yellow 。 除了強制和動畫之外,本機設定的屬性值具有最高的優先順序,因此按鈕會是紅色的,即使是在滑鼠變換上也一樣。 但是,如果您從按鈕移除本機設定的值,則會從樣式中取得其 Background 值。 在樣式中,觸發程式會優先使用,因此按鈕在滑鼠上會是黃色,否則為藍色。 此範例會取代按鈕的預設值 ControlTemplate ,因為預設範本具有硬式編碼的滑鼠變換 Background 值。

相依性屬性優先順序清單

下列清單是將運行時間值指派給相依性屬性時,屬性系統所使用的優先順序。 最高優先順序會先列出。

  1. 屬性系統強制型轉: 如需強制強制的詳細資訊,請參閱 強制和動畫

  2. 作用中動畫或具有 Hold 行為的動畫: 若要有實際效果,動畫值必須優先于基底值(非固定值),即使基底值是在本機設定也一樣。 如需詳細資訊,請參閱 強制和動畫

  3. 本機值 。 您可以透過「包裝函式」屬性來設定本機值,這相當於在 XAML 中設定屬性或屬性元素,或使用特定實例的屬性呼叫 SetValue API。 透過系結或資源設定的本機值,其優先順序會與直接設定的值相同。

  4. TemplatedParent 範本屬性值 。 如果專案是由範本 ( ControlTemplateDataTemplate ) 所建立,則專案具有 TemplatedParent 。 如需詳細資訊,請參閱 TemplatedParent 。 在 指定的 TemplatedParent 範本內,優先順序為:

    1. 觸發程序。

    2. 屬性集,通常是透過 XAML 屬性。

  5. 隱含樣式 。 僅適用於 Style 屬性。 值 Style 是任何樣式資源,其 TargetType 值符合專案類型。 樣式資源必須存在於頁面或應用程式中。 查閱隱含樣式資源不會延伸至主題中的樣式資源。

  6. 樣式觸發程序: 樣式觸發程式是明確或隱含樣式內的觸發程式。 樣式必須存在於頁面或應用程式中。 預設樣式中的觸發程式優先順序較低。

  7. 樣板觸發程序: 範本觸發程式是從直接套用的範本,或從樣式內的範本觸發程式。 樣式必須存在於頁面或應用程式中。

  8. 樣式 setter 值 。 樣式 setter 值是由 樣式內套 Setter 用的值。 樣式必須存在於頁面或應用程式中。

  9. 預設樣式 ,也稱為 主題樣式 。 如需詳細資訊,請參閱 預設 (主題) 樣式 。 在預設樣式內,優先順序為:

    1. 作用中觸發程式。

    2. 制定。

  10. 繼承: 子項目的某些相依性屬性會從父元素繼承其值。 因此,可能不需要在整個應用程式的每個元素上設定屬性值。 如需詳細資訊,請參閱 屬性值繼承

  11. 相依性屬性中繼資料 的預設值:相依性屬性可以在該屬性的屬性系統註冊期間設定預設值。 繼承相依性屬性的衍生類別可以根據每個類型覆寫相依性屬性中繼資料(包括預設值)。 如需詳細資訊,請參閱 相依性屬性中繼資料 。 對於繼承的屬性,父元素的預設值優先于子項目的預設值。 因此,如果未設定可繼承的屬性,則會使用根或父系的預設值,而不是子項目的預設值。

TemplatedParent

TemplatedParent 優先順序不適用於直接在標準應用程式標記中宣告的專案屬性。 概 TemplatedParent 念僅適用于透過範本應用程式存在於視覺化樹狀結構中的子專案。 當屬性系統搜尋 由 指定的 TemplatedParent 範本來尋找元素的屬性值時,它會搜尋建立專案的範本。 來自 TemplatedParent 範本的屬性值通常就像是元素上的本機設定值,但優先順序低於實際本機值,因為範本可能會共用。 如需詳細資訊,請參閱TemplatedParent

Style 屬性

優先順序相同的順序會套用至所有相依性屬性,但 屬性除外 Style 。 屬性 Style 是唯一的,因為它本身無法設定樣式。 不建議強制或製作屬性的動畫 Style 效果(而且 Style 動畫屬性需要自訂動畫類別)。 因此,並非所有優先順序專案都適用。 只有三種方式可以設定 Style 屬性:

  • 明確樣式: 專案的 Style 屬性會直接設定。 Style屬性值的作用就像是本機值,且優先順序清單中 的專案 3 具有相同的優先順序。 在大部分情況下,明確樣式不會內嵌定義,而是明確參考為資源,例如 Style="{StaticResource myResourceKey}"

  • 隱含樣式: Style專案的屬性未直接設定。 相反地,當樣式存在於頁面或應用程式內的某個層級時,會套用樣式,並具有符合樣式所套用專案類型的資源索引鍵,例如 <Style TargetType="x:Type Button"> 。 型別必須完全相符,例如 <Style TargetType="x:Type Button"> 即使衍生自 Button ,也不會套用至 MyButtonMyButton 別。 Style屬性值的優先順序與優先順序清單中的 專案 5 相同。 您可以藉由呼叫 DependencyPropertyHelper.GetValueSource 方法、傳入 Style 屬性,以及檢查 ImplicitStyleReference 結果,來偵測隱含樣式值。

  • 預設樣式也稱為主題樣式Style專案的屬性未直接設定。 相反地,它來自 WPF 簡報引擎的執行時間主題評估。 在執行時間之前, Style 屬性值為 nullStyle屬性值的優先順序與優先順序清單中的 專案 9 相同。

預設 (主題) 樣式

隨 WPF 隨附的每個控制項都有預設樣式,可能會因主題而有所不同,這就是為什麼預設樣式有時稱為 主題樣式 的原因。

ControlTemplate是控制項預設樣式內的重要專案。 ControlTemplate 是樣式屬性的 Template setter 值。 如果預設樣式未包含範本,則沒有自訂範本作為自訂樣式一部分的控制項就不會有視覺外觀。 範本不僅會定義控制項的視覺外觀,也會定義範本視覺化樹狀結構中屬性與對應控制項類別之間的連接。 每個控制項都會公開一組屬性,這些屬性可以影響控制項的視覺外觀,而不需要取代範本。 例如,請考慮控制項的預設視覺外觀 Thumb ,這是 ScrollBar 元件。

Thumb控制項具有特定的可自訂屬性。 控制項的預設範本 Thumb 會建立基本結構或視覺化樹狀結構,其中包含數個巢狀 Border 元件來建立斜面外觀。 在範本中,要由 Thumb 類別自訂的屬性會透過 TemplateBinding 公開。 控制項的預設範本 Thumb 具有各種框線屬性,這些屬性會與 或 BorderThicknessBackground 屬性共用範本系結。 但是,當屬性或視覺排列的值在範本中硬式編碼,或系結至直接來自主題的值時,您只能藉由取代整個範本來變更這些值。 一般而言,如果屬性來自樣板化父系,而且不會由 TemplateBinding 公開,則屬性值無法由樣式變更,因為沒有方便的方法可以設定目標。 但是,該屬性仍可能會受到套用範本中的屬性值繼承或預設值的影響。

預設樣式會在其定義中指定 TargetType 。 執行時間主題評估會將 TargetType 預設樣式的 與 DefaultStyleKey 控制項的 屬性相符。 相反地,隱含樣式的查閱行為會使用 控制項的實際類型。 的值 DefaultStyleKey 會由衍生類別繼承,因此可能沒有相關聯樣式的衍生專案會取得預設的視覺外觀。 例如,如果您衍生 MyButtonButtonMyButton 將會繼承 的預設範本 Button 。 衍生類別可以覆寫相依性屬性中繼資料中的 預設值 DefaultStyleKey 。 因此,如果您想要 針對 使用不同的視覺標記法 MyButton ,您可以覆寫 上的 MyButton 相依性屬性中繼資料 DefaultStyleKey ,然後定義相關的預設樣式,包括範本,以便搭配控制項 MyButton 封裝。 如需詳細資訊,請參閱 控制撰寫概觀

動態資源

動態資源 參考和系結作業的優先順序為設定的位置。 例如,套用至本機值的動態資源優先順序與優先順序清單中的 專案 3 相同。 另一個範例是,套用至預設樣式內屬性 setter 的動態資源系結與優先順序清單中的 專案 9 相同。 由於動態資源參考和系結必須從應用程式的執行時間狀態取得值,因此判斷任何指定屬性之屬性值優先順序的程式會延伸到執行時間。

動態資源參考在技術上不是屬性系統的一部分,而且有自己的查閱順序與優先順序清單 互動 。 基本上,動態資源參考的優先順序是:元素到頁面根目錄、應用程式、主題,然後是系統。 如需詳細資訊,請參閱 XAML 資源

雖然動態資源參考和系結具有設定位置的優先順序,但值會延後。 因此,如果您將動態資源或系結設定為本機值,則本機值的任何變更會完全取代動態資源或系結。 即使您呼叫 ClearValue 方法來清除本機設定的值,也不會還原動態資源或系結。 事實上,如果您在具有動態資源或系結的屬性上呼叫 ClearValue (沒有常值本機值),則會清除動態資源或系結。

SetCurrentValue

方法 SetCurrentValue 是設定屬性的另一種方式,但它不在 優先順序清單中 SetCurrentValue 可讓您變更屬性的值,而不覆寫先前值的來源。 例如,如果屬性是由觸發程式設定,然後使用 指派另一個值 SetCurrentValue ,則下一個觸發程式動作會將屬性設定回觸發程式值。 每當您想要設定屬性值時,即可使用該 SetCurrentValue 值,而不需提供本機值的優先順序層級。 同樣地,您可以使用 SetCurrentValue 來變更屬性的值,而不覆寫系結。

強制和動畫

強制和動畫都會在基底值 運作。 基 底值 是優先順序最高的相依性屬性值,其決定方式是透過優先順序清單 向上評估 ,直到達到專案 2 為止。

如果動畫未針對特定行為指定 FromTo 屬性值,或動畫在完成時刻意還原為基底值,則基底值可能會影響動畫值。 若要在實務上看到這種情況,請執行 目標值 範例應用程式。 在範例中,針對矩形高度,請嘗試設定與任何 From 值不同的初始本機值。 範例動畫會使用 From 值而非基底值,立即開始。 藉由指定 StopFillBehavior ,完成動畫時,動畫會將屬性值重設為其基底值。 一般優先順序用於動畫結束後的基底值判斷。

多個動畫可以套用至單一屬性,每個動畫都有不同的優先順序。 WPF 呈現引擎可能會根據動畫的定義方式和動畫類型,將動畫值複合在一起,而不是套用優先順序最高的動畫。 如需詳細資訊,請參閱動畫概觀

強制設定位於優先順序清單 端。 即使是執行中的動畫也受限於值強制。 WPF 中的某些現有相依性屬性具有內建強制。 針對自訂相依性屬性,您可以撰寫 CoerceValueCallback 在建立屬性時傳遞做為中繼資料一部分的 來定義強制行為。 您也可以覆寫衍生類別中該屬性的中繼資料,以覆寫現有屬性的強制行為。 強制型轉會以強制型轉的條件約束在當時存在時套用的方式與基底值互動,但基底值仍會保留。 因此,如果稍後會解除強制的條件約束,強制會傳回最接近基底值的值,而且在解除所有條件約束後,屬性的強制影響可能會停止。 如需強制行為的詳細資訊,請參閱 相依性屬性回呼和驗證

觸發程式列為

控制項通常會將觸發程式列為定義為其 預設樣式 的一部分。 在控制項上設定本機屬性可能會與這些觸發程式發生衝突,以防止觸發程式以視覺方式或行為方式回應使用者驅動事件。 屬性觸發程式的常見用法是控制狀態屬性,例如 IsSelectedIsEnabled 。 例如,根據預設,當 停用 時 Button ,主題樣式觸發程式 ( IsEnabledfalse ) 會設定 Foreground 值,使 Button 顯示為灰色。如果您已設定本機 Foreground 值,則較高的優先順序本機屬性值將會覆寫主題樣式 Foreground 值,即使停用也一樣 Button 。 設定覆寫控制項之主題層級觸發程式列為的屬性值時,請小心不要過度干擾該控制項的預期使用者體驗。

ClearValue

方法 ClearValue 會清除專案相依性屬性的任何本機套用值。 但是,呼叫 ClearValue 並不保證在屬性註冊期間中繼資料中建立的預設值是新的有效值。 優先順序清單中的 所有其他參與者仍然使用中 ,而且只會移除本機設定的值。 例如,如果您在具有主題樣式的屬性上呼叫 ClearValue ,主題樣式值將會套用為新值,而不是以中繼資料為基礎的預設值。 如果您想要將屬性值設定為已註冊的中繼資料預設值,請查詢相依性屬性中繼資料以取得預設中繼資料值,並在本機設定屬性值並呼叫 SetValue

另請參閱