相依性屬性總覽 (WPF .NET)

Windows Presentation Foundation (WPF) 提供一組可用來擴充類型的屬性功能之服務。 這些服務統稱為 WPF 屬性系統。 WPF 屬性系統支援的屬性稱為相依性屬性。 本總覽描述 WPF 屬性系統和相依性屬性的功能,包括如何在 XAML 和程式碼中使用現有的相依性屬性。 本概觀也介紹相依性屬性的特製化層面,例如相依性屬性中繼資料,以及如何在自訂類別中建立您自己的相依性屬性。

重要

.NET 5 (和 .NET Core) 的桌面指南檔正在結構中。

必要條件

本文假設您具備 .NET 型別系統和麵向物件程式設計的基本知識。 若要遵循本文中的範例,可協助您瞭解 XAML 並知道如何撰寫 WPF 應用程式。 如需詳細資訊,請參閱逐步解說︰我的第一個 WPF 桌面應用程式

相依性屬性與 CLR 屬性

WPF 屬性通常會公開為標準的 .NET 屬性。 您可以在基本層級與這些屬性互動,而且永遠不知道它們是實作為相依性屬性。 但是,熟悉 WPF 屬性系統的部分或全部功能,將有助於您利用這些功能。

相依性屬性的目的是要提供一種方法,根據其他輸入的值來計算屬性值,例如:

  • 系統屬性,例如主題和使用者喜好設定。
  • 即時屬性判斷機制,例如資料系結和動畫/分鏡腳本。
  • 多用途範本,例如資源和樣式。
  • 與專案樹狀結構中的其他元素之間的父子式關聯性已知的值。

此外,相依性屬性也可以提供下列各項:

  • 獨立驗證。
  • 預設值。
  • 可監視其他屬性變更的回呼。
  • 可根據執行時間資訊強制轉型屬性值的系統。

衍生的類別可以藉由覆寫相依性屬性的中繼資料,來變更現有屬性的某些特性,而不是覆寫現有屬性的實際執行,或建立新的屬性。

在 SDK 參考中,您可以在該屬性的 [managed 參考] 頁面上,找到相依性屬性資訊區段,以識別相依性屬性。 相依性屬性資訊區段包含該相依性 DependencyProperty 屬性之識別碼欄位的連結。 它也包含該屬性的中繼資料選項清單、每個類別的覆寫資訊,以及其他詳細資料。

相依性屬性支援 CLR 屬性

相依性屬性和 WPF 屬性系統會藉由提供可支援屬性的類型來擴充屬性功能,以替代支援具有私用欄位之屬性的標準模式。 這個類型的名稱為 DependencyProperty。 定義 WPF 屬性系統的另一個重要的類型是 DependencyObject ,它會定義可註冊並擁有相依性屬性的基類。

以下是一些常用的術語:

  • 相依性屬性,這個 屬性 是由所支援的屬性 DependencyProperty

  • 相依性 屬性識別碼,這個識別碼是 DependencyProperty 在註冊相依性屬性時取得為傳回值的實例,然後儲存為類別的靜態成員。 許多與 WPF 屬性系統互動的 Api 都會使用相依性屬性識別碼作為參數。

  • CLR 「包裝 函式」,也就是屬性的和實作為 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 中的 xamlxaml 語法詳細資料

下列 XAML 範例顯示另一個使用屬性專案語法的按鈕背景,而不是使用屬性語法。 XAML 不會設定簡單的純色,而是將 button 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 物件。 使用資料系結時,判斷最終屬性值會延後到執行時間,此時會從資料來源取得值。

下列範例會 Content 使用 XAML 中宣告的系結來設定的屬性 Button 。 繫結使用繼承的資料內容和 XmlDataProvider 資料來源 (未顯示)。 系結本身會指定資料來源中的來源屬性 XPath

<Button Content="{Binding Source={StaticResource TestData}, XPath=test[1]/@text}"/>

注意

系結會被視為區域值,這表示如果您設定另一個區域值,就會刪除系結。 如需詳細資料,請參閱相依性 屬性值優先順序

相依性屬性或 DependencyObject 類別,不會以原生方式支援資料系結 INotifyPropertyChanged DependencyObject 作業之來源屬性值變更的通知。 如需有關如何建立可將變更報告至資料系結目標之屬性的詳細資訊,請參閱資料系結 總覽

樣式

樣式和範本是使用相依性屬性的令人信服的理由。 樣式特別適用于設定定義應用程式 UI 的屬性。 樣式通常會定義為 XAML 中的資源。 樣式會與屬性系統互動,因為它們通常會包含特定屬性的「setter」,而「觸發程式」會根據另一個屬性的運行時間值來變更屬性值。

下列範例會建立簡單樣式,此樣式會定義于字典內 Resources (不會顯示) 。 然後該樣式會直接套用到的 Style 屬性 Button 。 樣式中的 setter 會將樣式 ButtonBackground 屬性設定為綠色。

<Style x:Key="GreenButtonStyle">
    <Setter Property="Control.Background" Value="Green"/>
</Style>
<Button Style="{StaticResource GreenButtonStyle}" Content="I am green"/>

如需詳細資訊,請參閱設定樣式和範本

動畫

相依性屬性可以動畫方式顯示。 當套用的動畫執行時,動畫值的優先順序高於任何其他屬性值(包括區域值)。

下列範例會將的 Background 屬性動畫 Button 。 技術上來說,屬性元素語法會將空白設定 SolidColorBrushBackground ,而的 Color 屬性 SolidColorBrush 則會以動畫顯示。

<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 來指定系結來源的屬性。 因此,子物件中的系結不需要指定來源,而且可以使用 DataContext 父物件中的繼承值 StackPanel 。 或者,子物件可以直接在中指定它自己的 DataContextSource Binding ,而不使用繼承的值。

<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 任何按鈕的屬性,但會指定一個具有本機 set 屬性的按鈕 Background 。 技術上來說,這個按鈕的 Background 屬性會設定兩次,雖然只有一個值會套用 — 具有最高優先順序的值。 本機設定的值具有最高優先順序,但不存在於此處的執行中動畫除外。 因此,第一個按鈕會使用本機設定的屬性值 Background ,而不是使用樣式 setter 值。 第二個按鈕沒有區域值,或其他值的優先順序高於樣式 setter,因此會使用屬性的樣式 setter 值 Background

<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 中呈現它們。 如需範例,請參閱 DockLeft 。 如需詳細資訊,請參閱 附加屬性總覽

另請參閱