相依性屬性值優先順序 (WPF .NET)
Windows Presentation Foundation (WPF) 屬性系統的工作會影響相依性屬性的值。 本文說明 WPF 屬性系統中不同屬性型輸入的優先順序如何決定相依性屬性的有效值。
必要條件
本文假設您具備相依性屬性的基本知識,而且您已閱讀 相依性屬性概觀。 若要遵循本文中的範例,如果您熟悉可延伸的應用程式標記語言(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
值。
相依性屬性優先順序清單
下列清單是將運行時間值指派給相依性屬性時,屬性系統所使用的優先順序。 最高優先順序會先列出。
屬性系統強制型轉: 如需強制強制的詳細資訊,請參閱 強制和動畫。
作用中動畫或具有 Hold 行為的動畫: 若要有實際效果,動畫值必須優先於基底值(非固定值),即使基底值是在本機設定也一樣。 如需詳細資訊,請參閱 強制和動畫。
本機值。 您可以透過「包裝函式」屬性來設定本機值,這相當於在 XAML 中設定屬性或屬性元素,或使用特定實例的屬性呼叫 SetValue API。 透過系結或資源設定的本機值,其優先順序會與直接設定的值相同。
TemplatedParent 範本屬性值。 如果專案是由樣本 (ControlTemplate或 DataTemplate) 所建立,則專案具有 TemplatedParent 。 如需詳細資訊,請參閱 TemplatedParent。 在 指定的
TemplatedParent
範本內,優先順序為:觸發程序。
屬性集,通常是透過 XAML 屬性。
隱含樣式。 僅適用於 Style 屬性。 值
Style
是任何樣式資源,其 TargetType 值符合項目類型。 樣式資源必須存在於頁面或應用程式中。 查閱隱含樣式資源不會延伸至主題中的樣式資源。樣式觸發程序: 樣式觸發程式是明確或隱含樣式內的觸發程式。 樣式必須存在於頁面或應用程式中。 默認樣式中的觸發程式優先順序較低。
樣板觸發程序: 範本觸發程式是從直接套用的範本,或從樣式內的範本觸發程式。 樣式必須存在於頁面或應用程式中。
樣式 setter 值。 樣式 setter 值是由 樣式內套 Setter 用的值。 樣式必須存在於頁面或應用程式中。
默認樣式,也稱為 主題樣式。 如需詳細資訊,請參閱 預設 (主題) 樣式。 在預設樣式內,優先順序為:
作用中觸發程式。
制定。
繼承: 子元素的某些相依性屬性會從父元素繼承其值。 因此,可能不需要在整個應用程式的每個元素上設定屬性值。 如需詳細資訊,請參閱 屬性值繼承。
相依性屬性元數據 的預設值:相依性屬性可以在該屬性的屬性系統註冊期間設定預設值。 繼承相依性屬性的衍生類別可以根據每個類型覆寫相依性屬性元數據(包括預設值)。 如需詳細資訊,請參閱 相依性屬性元數據。 對於繼承的屬性,父元素的預設值優先於子元素的預設值。 因此,如果未設定可繼承的屬性,則會使用根或父系的預設值,而不是子元素的預設值。
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
,也不會套用至MyButton
型MyButton
別。Style
屬性值的優先順序與優先順序清單中的專案 5 相同。 您可以藉由呼叫 DependencyPropertyHelper.GetValueSource 方法、傳入Style
屬性,以及檢查ImplicitStyleReference
結果,來偵測隱含樣式值。預設樣式也稱為主題樣式。
Style
項目的屬性未直接設定。 相反地,它來自 WPF 簡報引擎的運行時間主題評估。 在執行時間之前,Style
屬性值為null
。Style
屬性值的優先順序與優先順序清單中的專案 9 相同。
預設 (主題) 樣式
隨 WPF 隨附的每個控件都有預設樣式,可能會因主題而有所不同,這就是為什麼預設樣式有時稱為 主題樣式的原因。
ControlTemplate是控件默認樣式內的重要專案。 ControlTemplate
是樣式屬性的 Template setter 值。 如果預設樣式未包含範本,則沒有自定義範本作為自定義樣式一部分的控件就不會有視覺外觀。 範本不僅會定義控件的視覺外觀,也會定義範本可視化樹狀結構中屬性與對應控件類別之間的連接。 每個控件都會公開一組屬性,這些屬性可以影響控件的視覺外觀,而不需要取代範本。 例如,請考慮控件的預設視覺外觀 Thumb ,這是 ScrollBar 元件。
Thumb控制件具有特定的可自定義屬性。 控件的預設範本 Thumb
會建立基本結構或可視化樹狀結構,其中包含數個巢狀 Border 元件來建立斜面外觀。 在範本中,要由 Thumb
類別自定義的屬性會透過 TemplateBinding公開。 控件的預設範本Thumb
具有各種框線屬性,這些屬性會與或BorderThickness等Background屬性共用範本系結。 但是,當屬性或視覺排列的值在範本中硬式編碼,或系結至直接來自主題的值時,您只能藉由取代整個範本來變更這些值。 一般而言,如果屬性來自樣板化父系,而且不會由 TemplateBinding
公開,則屬性值無法由樣式變更,因為沒有方便的方法可以設定目標。 但是,該屬性仍可能會受到套用範本中的屬性值繼承或預設值的影響。
預設樣式會在其定義中指定 TargetType 。 運行時間主題評估會將 TargetType
預設樣式的 與 DefaultStyleKey 控件的 屬性相符。 相反地,隱含樣式的查閱行為會使用 控件的實際類型。 的值 DefaultStyleKey
會由衍生類別繼承,因此可能沒有相關聯樣式的衍生專案會取得預設的視覺外觀。 例如,如果您衍生 MyButton
自 Button, MyButton
將會繼承的默認範本 Button
。 衍生類別可以覆寫相依性屬性元數據中的 預設值 DefaultStyleKey
。 因此,如果您想要 針對 使用不同的視覺表示法MyButton
,您可以覆寫 上的MyButton
相依性屬性元數據DefaultStyleKey
,然後定義相關的默認樣式,包括範本,以便搭配控件MyButton
封裝。 如需詳細資訊,請參閱 控制撰寫概觀。
動態資源
動態資源 參考和系結作業的優先順序為設定的位置。 例如,套用至本機值的動態資源優先順序與優先順序清單中的專案 3 相同。 另一個範例是,套用至默認樣式內屬性 setter 的動態資源系結與優先順序清單中的專案 9 相同。 由於動態資源參考和系結必須從應用程式的運行時間狀態取得值,因此判斷任何指定屬性之屬性值優先順序的程式會延伸到運行時間。
動態資源參考在技術上不是屬性系統的一部分,而且有自己的查閱順序與優先順序清單互動。 基本上,動態資源參考的優先順序是:元素到頁面根目錄、應用程式、主題,然後是系統。 如需詳細資訊,請參閱 XAML 資源。
雖然動態資源參考和系結具有設定位置的優先順序,但值會延後。 因此,如果您將動態資源或系結設定為本機值,則本機值的任何變更會完全取代動態資源或系結。 即使您呼叫 ClearValue 方法來清除本機設定的值,也不會還原動態資源或系結。 事實上,如果您在具有動態資源或系結的屬性上呼叫 ClearValue
(沒有常值本機值),則會清除動態資源或系結。
SetCurrentValue
方法 SetCurrentValue 是設定屬性的另一種方式,但它不在 優先順序清單中。 SetCurrentValue
可讓您變更屬性的值,而不覆寫先前值的來源。 例如,如果屬性是由觸發程式設定,然後使用 指派另一個值 SetCurrentValue
,則下一個觸發程式動作會將屬性設定回觸發程式值。 每當您想要設定屬性值時,即可使用該 SetCurrentValue
值,而不需提供本機值的優先順序層級。 同樣地,您可以使用 SetCurrentValue
來變更屬性的值,而不覆寫系結。
強制和動畫
強制和動畫都會在基底值上運作。 基底值是優先順序最高的相依性屬性值,其決定方式是透過優先順序清單向上評估,直到達到專案 2 為止。
如果動畫未針對特定行為指定 From 和 To 屬性值,或動畫在完成時刻意還原為基底值,則基底值可能會影響動畫值。 若要在實務上看到這種情況,請執行 目標值 範例應用程式。 在範例中,針對矩形高度,請嘗試設定與任何 From
值不同的初始本機值。 範例動畫會使用 From
值而非基底值,立即開始。 藉由指定 Stop 為 FillBehavior,完成動畫時,動畫會將屬性值重設為其基底值。 一般優先順序用於動畫結束后的基底值判斷。
多個動畫可以套用至單一屬性,每個動畫都有不同的優先順序。 WPF 呈現引擎可能會根據動畫的定義方式和動畫類型,將動畫值複合在一起,而不是套用優先順序最高的動畫。 如需詳細資訊,請參閱動畫概觀。
強制設定位於優先順序清單頂端。 即使是執行中的動畫也受限於值強制。 WPF 中的某些現有相依性屬性具有內建強制。 針對自定義相依性屬性,您可以撰寫 CoerceValueCallback 在建立屬性時傳遞做為元數據一部分的 來定義強制行為。 您也可以覆寫衍生類別中該屬性的元數據,以覆寫現有屬性的強制行為。 強制型轉會以強制型轉的條件約束在當時存在時套用的方式與基底值互動,但基底值仍會保留。 因此,如果稍後會解除強制的條件約束,強制會傳回最接近基底值的值,而且在解除所有條件約束后,屬性的強制影響可能會停止。 如需強制行為的詳細資訊,請參閱 相依性屬性回呼和驗證。
觸發程序行為
控件通常會將觸發程式行為定義為其 默認樣式的一部分。 在控件上設定本機屬性可能會與這些觸發程式發生衝突,以防止觸發程式以視覺方式或行為方式回應用戶驅動事件。 屬性觸發程式的常見用法是控制狀態屬性,例如 IsSelected 或 IsEnabled。 例如,根據預設,當 停用 時 Button ,主題樣式觸發程式 (IsEnabled
是 false
) 會設定 Foreground 值,使 Button
顯示為灰色。如果您已設定本機 Foreground
值,則較高的優先順序本機屬性值將會覆寫主題樣式 Foreground
值,即使停用也一樣 Button
。 設定覆寫控件之主題層級觸發程式行為的屬性值時,請小心不要過度干擾該控件的預期用戶體驗。
ClearValue
方法 ClearValue 會清除專案相依性屬性的任何本機套用值。 但是,呼叫 ClearValue
並不保證在屬性註冊期間元數據中建立的預設值是新的有效值。 優先順序清單中的所有其他參與者仍然使用中,而且只會移除本機設定的值。 例如,如果您在具有主題樣式的屬性上呼叫 ClearValue
,主題樣式值將會套用為新值,而不是以元數據為基礎的預設值。 如果您要將屬性值設定為已註冊的元資料預設值,請查詢相依性屬性元資料以取得預設元資料值,並在本機設定屬性值並呼叫 SetValue。