相依性屬性概觀 (WPF .NET)
Windows Presentation Foundation (WPF) 提供一組可用來擴充類型的屬性功能之服務。 整體而言,這些服務稱為 WPF 屬性系統。 受到 WPF 屬性系統支援的屬性則稱為相依性屬性。 本概觀描述 WPF 屬性系統和相依性屬性的功能,包括如何在 XAML 和程式碼中使用現有的相依性屬性。 本概觀也介紹相依性屬性的特製化層面,例如相依性屬性中繼資料,以及如何在自訂類別中建立您自己的相依性屬性。
必要條件
本主題假設使用者對 NET 類型系統和物件導向程式設計有基本的認識。 若遵循本文中的範例,有助您了解 XAML 並知道如何撰寫 WPF 應用程式。 如需詳細資訊,請參閱教學課程:使用 .NET 建立新的 WPF 應用程式。
相依性屬性與 CLR 屬性
WPF 屬性通常會公開為標準 .NET 屬性。 您可能會在基本層級與這些屬性互動,且永遠不會知道這些屬性會實作為相依性屬性。 但如果您熟悉 WPF 屬性系統的某些或所有功能,有助您善加運用這些功能。
相依性屬性是為了提供一個方式,根據其他輸入的值來計算屬性值,例如:
- 系統屬性,例如佈景主題和使用者喜好設定。
- Just-In-Time 屬性決策機制,例如資料繫結和動畫/腳本。
- 多用途範本,例如資源和樣式。
- 透過父子式關聯性與項目樹狀結構中其他項目的已知值。
此外,相依性屬性也可以提供以下功能:
- 獨立式驗證。
- 預設值。
- 監視其他屬性變更的回呼。
- 可依執行階段資訊強制轉型屬性值的系統。
衍生的類別可透過覆寫相依性屬性中繼資料,而不是覆寫現有屬性的實際實作或建立新屬性,來變更現有屬性的某些特性。
在 SDK 參考中,您可以在該屬性的 Managed 參考頁面出現相依性屬性資訊區段時,加以識別相依性屬性。 [相依性屬性資訊] 區段包含該相依性屬性 DependencyProperty 識別碼欄位的連結。 這也包含該屬性的中繼資料選項清單、各類別的覆寫資訊和其他詳細資料。
相依性屬性支援 CLR 屬性
相依性屬性和 WPF 屬性系統透過提供支援屬性的類型來擴充屬性功能,作為支援有私用欄位屬性之標準模式的替代方式。 這個類型的名稱為 DependencyProperty。 另一個定義 WPF 屬性系統的重要類型是 DependencyObject,這會定義可註冊和擁有相依性屬性的基底類別。
以下列出幾個常用術語:
相依性屬性是由 DependencyProperty 支援的屬性。
相依性屬性識別碼︰此為
DependencyProperty
執行個體,在登錄相依性屬性時當成傳回值取得,然後儲存為類別的靜態成員。 與 WPF 屬性系統互動的許多 API 都會使用相依性屬性識別碼做為參數。CLR “wrapper”,這是該屬性的
get
和set
實作。 這些實作會用於 GetValue 和 SetValue 呼叫中,並加入相依性屬性識別碼。 如此一來,WPF 屬性系統就會提供該屬性的備份。
下例定義 IsSpinning
相依性屬性,可向其支援的屬性顯示 DependencyProperty
識別碼關聯性。
public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.Register(
"IsSpinning", typeof(bool),
typeof(MainWindow)
);
public bool IsSpinning
{
get => (bool)GetValue(IsSpinningProperty);
set => SetValue(IsSpinningProperty, value);
}
Public Shared ReadOnly IsSpinningProperty As DependencyProperty =
DependencyProperty.Register("IsSpinning", GetType(Boolean), GetType(MainWindow))
Public Property IsSpinning As Boolean
Get
Return GetValue(IsSpinningProperty)
End Get
Set(value As Boolean)
SetValue(IsSpinningProperty, value)
End Set
End Property
屬性的命名慣例及其支援的 DependencyProperty 欄位很重要。 欄位名稱一律是屬性名稱,後綴尾碼 Property
。 如需此慣例及其原因的詳細資訊,請參閱自訂相依性屬性。
設定屬性值
您可以在程式碼或 XAML 中設定屬性。
在 XAML 中設定屬性值
下列 XAML 範例將按鈕的背景色彩設定為紅色。 XAML 屬性的字串值是透過 WPF XAML 剖析器轉換成 WPF 類型來進行類型轉換。 在產生的程式碼中,WPF 類型是 Color,並採用 SolidColorBrush 方法。
<Button Content="I am red" Background="Red"/>
XAML 支援數種設定屬性的語法形式。 特定屬性所使用的語法取決於該屬性使用的實值型別和其他因素,例如有無類型轉換器。 如需設定屬性之 XAML 語法的詳細資訊,請參閱 WPF 中的 XAML 和 XAML 語法詳細資料。
下列 XAML 範例顯示另一個使用 Property 項目語法 (而非使用屬性語法) 的按鈕背景。 XAML 並不會設定簡單的純色,而是會將按鈕 Background
屬性設定為影像。 項目代表該影像,而巢狀項目則會指定該影像的來源。
<Button Content="I have an image background">
<Button.Background>
<ImageBrush ImageSource="stripes.jpg"/>
</Button.Background>
</Button>
在程式碼中設定屬性
在程式碼中設定相依性屬性值,通常只要呼叫 CLR「包裝函式」公開的 set
實作即可︰
Button myButton = new();
myButton.Width = 200.0;
Dim myButton As New Button With {
.Width = 200.0
}
取得屬性值,其實就是呼叫 get
「包裝函式」實作︰
double whatWidth = myButton.Width;
Dim whatWidth As Double = myButton.Width
您也可以直接呼叫屬性系統 API GetValue 和 SetValue。 直接呼叫 API 適合某些案例,但通常不適用於您使用現有屬性的情況。 一般而言,包裝函式更方便,也更好公開開發人員工具屬性。
屬性也可以在 XAML 中設定,稍後再於程式碼中透過程式碼後置存取。 如需詳細資訊,請參閱 WPF 中的程式碼後置和 XAML。
相依性屬性提供的屬性功能
不同於欄位所支援的屬性,相依性屬性會擴充屬性的功能。 新增的功能通常代表或支援下列其中一項功能:
資源
您可以參考資源來設定相依性屬性值。 資源通常指定為頁面根項目或應用程式的 Resources
屬性值 (這些位置最方便存取資源)。 在此範例中,我們會定義 SolidColorBrush 資源:
<StackPanel.Resources>
<SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</StackPanel.Resources>
現在已定義資源,我們可參考資源來提供 Background
屬性的值:
<Button Background="{DynamicResource MyBrush}" Content="I am gold" />
在 WPF XAML 中,您可以使用靜態或動態資源參考。 此特定資源會參考為 DynamicResource。 動態資源參考只能用來設定相依性屬性,因此這是 WPF 屬性系統所啟用的動態資源參考用途。 如需詳細資訊,請參閱 XAML 資源。
注意
資源視為區域數值,這表示若設定另一個區域數值,就會排除資源參考。 如需詳細資訊,請參閱相依性屬性值優先順序。
資料繫結
相依性屬性可以透過資料繫結參考值。 資料繫結的運作是透過 XAML 中的特定標記延伸語法,或程式碼中的 Binding 物件。 使用資料繫結,最後一個屬性值判定會延後到執行階段,此時已從資料來源取得值。
下列範例就是在 XAML 中使用宣告的繫結來設定 Button 的 Content 屬性。 繫結使用繼承的資料內容和 XmlDataProvider 資料來源 (未顯示)。 繫結本身會指定資料來源內 XPath 的來源屬性。
<Button Content="{Binding Source={StaticResource TestData}, XPath=test[1]/@text}"/>
注意
繫結視為區域數值,這表示若設定另一個區域數值,就會排除繫結。 如需詳細資訊,請參閱相依性屬性值優先順序。
相依性屬性 (或 DependencyObject 類別) INotifyPropertyChanged 並不原生支援資料繫結作業的 DependencyObject
來源屬性值中的變更通知。 如需建立資料繫結所用屬性的相關資訊,該資料繫結可以報告資料繫結目標的變更,請參閱資料繫結概觀。
樣式
樣式和範本是使用相依性屬性的絕佳理由。 對於設定定義應用程式 UI 的屬性而言,樣式特別實用。 樣式通常會定義為 XAML 中的資源。 樣式與屬性系統互動,因為樣式通常包含特定屬性的 "setter",並根據另一個屬性的執行階段值來變更屬性值的「觸發程序」。
下列範例會建立簡單的樣式,而該樣式會在 Resources 字典內加以定義 (未顯示)。 然後,該樣式會直接套用至 Style 的 Button 屬性。 樣式中的 setter 會將樣式 Button
的 Background 屬性設定為綠色。
<Style x:Key="GreenButtonStyle">
<Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}" Content="I am green"/>
如需詳細資訊,請參閱設定樣式和範本。
動畫
相依性屬性可以動畫方式顯示。 在系統執行套用的動畫時,動畫值的優先順序會高於任何其他屬性值 (含本機值)。
下列範例會以動畫顯示 Button 的 Background 屬性。 技術上來說,屬性項目語法會將空白 SolidColorBrush 設定為 Background
,而 SolidColorBrush
的 Color 屬性會以動畫顯示。
<Button Content="I am animated">
<Button.Background>
<SolidColorBrush x:Name="AnimBrush"/>
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard>
<Storyboard>
<ColorAnimation
Storyboard.TargetName="AnimBrush"
Storyboard.TargetProperty="(SolidColorBrush.Color)"
From="Blue" To="White" Duration="0:0:1"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
中繼資料覆寫
衍生來自原先註冊相依性屬性的類別時,您可以覆寫該屬性的中繼資料,以變更相依性屬性的特定行為。 覆寫中繼資料會使用 DependencyProperty 識別碼,而且不需要重新實作該屬性。 屬性系統會以原生方式處理中繼資料變更。 每個類別都可能依每個類型,保存繼承自基底類別之所有屬性的個別中繼資料。
下列範例會覆寫相依性屬性的中繼資料 DefaultStyleKey。 覆寫此特定相依性屬性的中繼資料,是建立可使用佈景主題預設樣式控制項之實作模式的一部分。
public class SpinnerControl : ItemsControl
{
static SpinnerControl() => DefaultStyleKeyProperty.OverrideMetadata(
typeof(SpinnerControl),
new FrameworkPropertyMetadata(typeof(SpinnerControl))
);
}
Public Class SpinnerControl
Inherits ItemsControl
Shared Sub New()
DefaultStyleKeyProperty.OverrideMetadata(GetType(SpinnerControl), New FrameworkPropertyMetadata(GetType(SpinnerControl)))
End Sub
End Class
如需有關覆寫或存取相依性屬性中繼資料的詳細資訊,請參閱覆寫相依性屬性的中繼資料。
屬性值繼承
項目可以繼承物件樹狀結構中的父代相依性屬性值。
注意
並非所有的相依性屬性都會啟用屬性值繼承行為,因為繼承的計算時間會影響效能。 屬性值繼承通常只會在建議適用性的案例中啟用。 您可以在<SDK 參考>的相依性屬性資訊一節中查看相依性屬性,檢查該相依性屬性是否有繼承行為。
下列範例顯示包含 DataContext 屬性的繫結,以指定繫結的來源。 因此,子物件中的繫結都不需要指定來源,並且可使用父系 StackPanel 物件中來自 DataContext
的繼承值。 此外,子物件還可直接在 Binding 中指定自己的 DataContext
或 Source,而不使用繼承值。
<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource TestData}}">
<Button Content="{Binding XPath=test[2]/@text}"/>
</StackPanel>
如需詳細資訊,請參閱屬性值繼承。
WPF 設計工具整合
實作為相依性屬性的自訂控制項會與 Visual Studio 的 WPF 設計工具整合。 其中一例就是能夠在 [屬性] 視窗中編輯直接和附加的相依性屬性。 如需詳細資訊,請參閱控制項撰寫概觀。
相依性屬性值優先順序
WPF 屬性系統中的任何屬性型輸入都可設定相依性屬性的值。 相依性屬性值有優先順序,所以屬性如何取得其值的各種案例才能夠以可預測的方式互動。
注意
在討論相依性屬性時,SDK 文件有時會使用詞彙「區域數值」或「本機設定值」。 本機設定值這個屬性值會直接設定在程式碼的物件執行個體上,或作為 XAML 中的項目屬性。
下個範例包含套用至任何按鈕 Background 屬性的樣式,但會指定有本機設定 Background
屬性的按鈕。 技術上來說,該按鈕的 Background
屬性已設定兩次,但只會套用一個值,也就是優先順序最高的值。 本機設定值的優先順序最高,但執行中的動畫則不存在於此。 因此,第二個按鈕會使用 Background
屬性的本機設定值,而非使用樣式 setter 值。 第一個按鈕沒有本機值或優先順序高於樣式 setter 的其他值,因此會使用 Background
屬性的樣式 setter 值。
<StackPanel>
<StackPanel.Resources>
<Style x:Key="{x:Type Button}" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Orange"/>
</Style>
</StackPanel.Resources>
<Button>I am styled orange</Button>
<Button Background="Pink">I am locally set to pink (not styled orange)</Button>
</StackPanel>
為什麼會有相依性屬性優先順序?
本機設定值優先順序高於樣式 setter 值,可支援項目屬性的本機控制項。 如需詳細資訊,請參閱相依性屬性值優先順序。
注意
WPF 項目上定義的許多屬性不是相依性屬性,因為相依性屬性通常只有在需要 WPF 屬性系統的功能時才會進行實作。 這些功能包括資料繫結、樣式、動畫、預設值支援、繼承、附加屬性和無效判定。
深入了解相依性屬性
元件開發人員或應用程式開發人員可能希望建立自己的相依性屬性,以便新增資料繫結或樣式支援等功能,或用於失效和值的強制轉型支援。 如需詳細資訊,請參閱自訂相依性屬性。
您不妨將相依性屬性視為公用屬性,任何可存取執行個體的呼叫端皆可存取或探索。 如需詳細資訊,請參閱相依性屬性的安全性。
附加屬性是支援 XAML 特殊語法的屬性類型。 附加屬性往往與通用語言執行平台屬性沒有 1:1 對應,而且不一定是相依性屬性。 附加屬性的主要用途是允許子項目向父項目回報屬性值,即使父項目和子項目並未擁有列為類別成員的該屬性。 有個主要案例是讓子項目通知父項目在 UI 中的呈現方式。 如需範例,請參閱 Dock 和 Left。 如需詳細資訊,請參閱附加屬性概觀。