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