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

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

重要

.NET 6 和 .NET 5 的桌面指南檔 (包括 .NET Core 3.1) 正在進行建構。

先決條件

本文假設您具備相依性屬性的基本知識,而且您已閱讀相 依性屬性概觀。 若要遵循本文中的範例,如果您熟悉可延伸應用程式標記語言 (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. 作用中動畫或具有保留行為的動畫。 若要有實際的效果,動畫值必須優先于基底 (非固定) 值,即使基底值是在本機設定也一樣。 如需詳細資訊,請參閱 強制型轉和動畫

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

  4. TemplatedParent 範本屬性值。 如果元素 TemplatedParent 是由範本所建立,則為 (ControlTemplateDataTemplate) 。 如需詳細資訊,請參閱 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 是唯一的,因為它本身無法設定樣式。 不建議在屬性 (強制或產生動畫效果,而讓屬性產生動畫 StyleStyle 需要自訂動畫類別) 。 因此,並非所有優先順序專案都適用。 只有三種方式可以設定 Style 屬性:

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

  • 隱含樣式: Style未直接設定專案的 屬性。 相反地,當樣式存在於頁面或應用程式內的某個層級時套用樣式,而且具有符合樣式所套用專案類型的資源索引鍵,例如 <Style TargetType="x:Type Button"> 。 此類型必須完全相符,例如 <Style TargetType="x:Type Button"> ,即使 MyButton 衍生自 Button ,也不會套用至 MyButton 類型。 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 為止。

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

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

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

觸發程式列為

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

ClearValue

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

另請參閱