1. 程式人生 > 實用技巧 >wpf依賴屬性概述

wpf依賴屬性概述

Windows Presentation Foundation (WPF) 提供一組服務,這些服務可用於擴充套件型別的屬性的功能。這些服務通常統稱為 WPF 屬性系統。由 WPF 屬性系統支援的屬性稱為依賴屬性。本概述介紹 WPF 屬性系統以及依賴屬性的功能。這包括如何在 XAML 和在程式碼中使用現有依賴屬性。本概述還介紹依賴屬性所特有的方面(如依賴屬性元資料),並說明如何在自定義類中建立自己的依賴屬性。

先決條件

本主題假設你在 .NET 型別系統和麵向物件的程式設計方面有一些基礎知識。為了能理解本主題中的示例,還應瞭解 XAML 並知道如何編寫 WPF 應用程式。有關詳細資訊,請參閱演練:我的第一個 WPF 桌面應用程式

依賴屬性和 CLR 屬性

在 WPF 中,屬性通常公開為標準 .NET屬性在基本級別,可以直接與這些屬性互動,而不必瞭解它們是以依賴屬性的形式實現的。但是,應當熟悉 WPF 屬性系統的部分或全部功能,以便利用這些功能。

依賴屬性的用途在於提供一種方法來基於其他輸入的值計算屬性值。這些其他輸入可能包括系統屬性(如主題和使用者首選項)、實時屬性確定機制(如資料繫結和動畫/情節提要)、重用模板(如資源和樣式)或者通過與元素樹中其他元素的父子關係來公開的值。另外,可以通過實現依賴屬性來提供獨立驗證、預設值、監視其他屬性的更改的回叫以及可以基於可能的執行時資訊來強制指定屬性值的系統。派生類還可以通過重寫依賴屬性元資料(而不是重寫現有屬性的實際實現或者建立新屬性)來更改現有屬性的某些具體特徵。

在 SDK 參考中,可以根據某個屬性的託管引用頁上是否存在“依賴屬性資訊”部分來確定該屬性是否為依賴屬性。“依賴屬性資訊”部分包括一個指向該依賴屬性的DependencyProperty識別符號欄位的連結,還包括一個為該屬性設定的元資料選項列表、每個類的重寫資訊以及其他詳細資訊。

依賴屬性支援 CLR 屬性

依賴屬性和 WPF 屬性系統通過提供一個支援屬性的型別來擴充套件屬性功能,這是使用專用欄位支援該屬性的標準模式的替代實現方法。此型別的名稱為DependencyProperty定義 WPF 屬性系統的另一個重要型別是DependencyObject

DependencyObject定義可以註冊和擁有依賴屬性的基類。

下面列出了與依賴屬性一起使用的術語:

  • 依賴屬性:DependencyProperty支援的屬性。

  • 依賴屬性識別符號:一個DependencyProperty例項,在註冊依賴屬性時以返回值形式獲取它,之後將其儲存為類的靜態成員。對於與 WPF 屬性系統互動的許多 API,此識別符號用作一個引數。

  • CLR“包裝器”:屬性的實際 get 和 set 實現。這些實現通過在GetValueSetValue呼叫中使用依賴屬性識別符號來併入依賴屬性識別符號,從而使用 WPF 屬性系統為屬性提供支援。

下面的示例定義IsSpinning依賴屬性,並說明DependencyProperty識別符號與它所支援的屬性之間的關係。

C#
public static readonly DependencyProperty IsSpinningProperty =
    DependencyProperty.Register(
    "IsSpinning", typeof(Boolean),
    typeof(MyCode)
    );
public bool IsSpinning
{
    get { return (bool)GetValue(IsSpinningProperty); }
    set { SetValue(IsSpinningProperty, value); }
}

屬性及其支援性DependencyProperty欄位的命名約定非常重要。欄位總是與屬性同名,但其後面追加了Property字尾。有關此約定及其原因的詳細資訊,請參閱自定義依賴屬性

設定屬性值

可以在程式碼或 XAML 中設定屬性。

在 XAML 中設定屬性值

下面的 XAML 示例將按鈕的背景色指定為紅色。此示例演示這樣一種情況:在所生成的程式碼中,WPF XAML 分析器將 XAML 屬性的簡單字串值型別轉換為 WPF 型別(一個Color,通過SolidColorBrush實現)。

XAML
<Button Background="Red" Content="Button!"/>

XAML 支援多種設定屬性的語法格式。要對特定的屬性使用哪種語法取決於該屬性所使用的值型別以及其他因素(例如,是否存在型別轉換器)。有關屬性設定的 XAML 語法的詳細資訊,請參閱XAML 概述 (WPF)XAML 語法詳述

作為非屬性語法的示例,下面的 XAML 示例顯示了另一種按鈕背景。這一次不是設定簡單的純色,而是將背景設定為影象,用一個元素表示該影象並將該影象的源指定為巢狀元素的屬性。這是屬性元素語法的示例。

XAML
<Button Content="Button!">
  <Button.Background>
    <ImageBrush ImageSource="wavy.jpg"/>
  </Button.Background>
</Button>

在程式碼中設定屬性

在程式碼中設定依賴屬性值通常只是對 CLR "包裝" 公開的集實現的呼叫。

C#
Button myButton = new Button();
myButton.Width = 200.0;

獲取屬性值實質上也是在呼叫 get“包裝器”實現:

C#
double whatWidth;
whatWidth = myButton.Width;

還可以直接呼叫屬性系統 ApiGetValueSetValue如果使用現有屬性(包裝更方便,併為開發人員工具提供更好的屬性公開),則通常不需要這樣做,但在某些情況下,可以直接呼叫 Api。

還可以在 XAML 中設定屬性,然後通過程式碼隱藏在程式碼中訪問這些屬性。有關詳細資訊,請參閱WPF 中的程式碼隱藏和 XAML

由依賴屬性提供的屬性功能

依賴屬性提供用來擴充套件屬性功能的功能,這與欄位支援的屬性相反。通常,此類功能代表或支援以下特定功能之一:

資源

依賴屬性值可以通過引用資源來設定。資源通常指定為頁面根元素或應用程式的Resources屬性值(通過這些位置可以非常方便地訪問資源)。以下示例演示如何定義SolidColorBrush資源。

XAML
<DockPanel.Resources>
  <SolidColorBrush x:Key="MyBrush" Color="Gold"/>
</DockPanel.Resources>

在定義該資源之後,可以引用該資源並使用它來提供屬性值:

XAML
<Button Background="{DynamicResource MyBrush}" Content="I am gold" />

這個特定資源稱為DynamicResource 標記擴充套件(在 WPF XAML 中,可以使用靜態或動態資源引用)。若要使用動態資源引用,必須設定為依賴屬性,因此它專門是由 WPF 屬性系統啟用的動態資源引用用法。有關詳細資訊,請參閱XAML 資源

備註

資源被視為本地值,這意味著,如果設定另一個本地值,該資源引用將被消除。有關詳細資訊,請參閱依賴屬性值優先順序

資料繫結

依賴屬性可以通過資料繫結來引用值。資料繫結通過特定標記擴充套件語法(在 XAML 中)或Binding物件(在程式碼中)起作用。使用資料繫結,最終屬性值的確定將延遲到執行時,在執行時,將從資料來源獲取屬性值。

以下示例使用在 XAML 中宣告的繫結來設定ButtonContent屬性。該繫結使用繼承的資料上下文和XmlDataProvider資料來源(未顯示)。繫結本身通過資料來源中的XPath指定所需的源屬性。

XAML
<Button Content="{Binding XPath=Team/@TeamName}"/>

備註

繫結被視為本地值,這意味著,如果設定另一個本地值,該繫結將被消除。有關詳細資訊,請參閱依賴屬性值優先順序

為了生成資料繫結操作的DependencyObject源屬性值的更改通知,依賴屬性或DependencyObject類本身不支援INotifyPropertyChanged有關如何建立要用在資料繫結中並且可以向資料繫結目標報告變化的屬性的詳細資訊,請參閱資料繫結概述

樣式

樣式和模板是使用依賴屬性的兩個主要激發方案。在設定定義應用程式使用者介面 (UI)的屬性時,樣式尤其有用。在 XAML 中,通常將樣式定義為資源。樣式與屬性系統互動,因為它們通常包含特定屬性的“資源庫”,以及基於另一個屬性的實時值更改屬性值的“觸發器”。

下面的示例建立一個簡單樣式(將在字典中定義Resources,而不會顯示),然後將該樣式直接應用於的Style屬性Button樣式中的資源庫將帶樣式ButtonBackground屬性設定為綠色。

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

有關詳細資訊,請參閱樣式設定和模板化

動畫

可以對依賴屬性進行動畫處理。在應用和執行動畫時,經過動畫處理的值的操作優先順序高於該屬性以其他方式具有的任何值(如本地值)。

以下示例在Button屬性上對Background進行動畫處理(從技術上講,通過使用屬性元素語法將空白SolidColorBrush指定為Background來對Background進行動畫處理,然後該SolidColorBrushColor屬性就是直接動畫處理過的屬性)。

XAML
<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的元資料。重寫此特定依賴屬性的元資料是某個實現模式的一部分,該模式建立可以使用主題中的預設樣式的控制元件。

C#
public class SpinnerControl : ItemsControl
{
    static SpinnerControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(
            typeof(SpinnerControl),
            new FrameworkPropertyMetadata(typeof(SpinnerControl))
        );
    }
}

有關替代或獲取屬性元資料的詳細資訊,請參閱依賴屬性元資料

屬性值繼承

元素可以從其在物件樹中的父級繼承依賴屬性的值。

備註

屬性值繼承行為並未針對所有依賴屬性在全域性啟用,因為繼承的計算時間確實會對效能產生一定的影響。屬性值繼承通常只有在特定方案指出適合使用屬性值繼承時才對屬性啟用。可以通過在 SDK 參考中檢視某個依賴屬性的依賴屬性資訊部分,來確定該依賴屬性是否繼承屬性值。

下面的示例演示一個繫結,並設定指定繫結(在前面的繫結示例中未顯示出來)的源的DataContext屬性。子物件中的任何後續繫結都無需指定源,它們可以使用父物件StackPanelDataContext的繼承值。(或者,子物件可以選擇直接在Binding中指定自己的DataContextSource,並且有意不將繼承值用於其繫結的資料上下文。)

XAML
<StackPanel Canvas.Top="50" DataContext="{Binding Source={StaticResource XmlTeamsSource}}">
  <Button Content="{Binding XPath=Team/@TeamName}"/>
</StackPanel>

有關詳細資訊,請參閱屬性值繼承

WPF 設計器整合

具有作為依賴屬性實現的屬性的自定義控制元件將接收適用於 Visual Studio 支援的相應 WPF 設計器。一個示例就是能夠在“屬性”**** 視窗中編輯直接依賴屬性和附加依賴屬性。有關詳細資訊,請參閱控制元件創作概述

依賴項屬性值優先順序

獲取依賴屬性的值時,獲得的值可能是通過參與 WPF 屬性系統的其他任一基於屬性的輸入而在該屬性上設定的。由於存在依賴屬性值優先順序,使得屬性獲取值的方式的各種方案得以按可預測的方式互動。

請看下面的示例。該示例包含適用於所有按鈕及其Background屬性的樣式,但也會指定一個具有本地設定的Background值的按鈕。

備註

SDK 文件在討論依賴屬性時有時會使用“本地值”或“本地設定的值”等術語。本地設定的值是指在程式碼中直接為物件例項設定的屬性值,或者在 XAML 中設定為元素特性的屬性值。

原則上,對於第一個按鈕,該屬性會設定兩次,但是僅應用一個值,即具有最高優先順序的值。本地設定的值具有最高優先順序(對於正在執行的動畫除外,但是在本示例中沒有應用動畫),因此,對於第一個按鈕的背景將使用本地設定的值,而不使用樣式資源庫值。第二個按鈕沒有本地值(而且沒有其他比樣式資源庫優先順序更高的值),因此該按鈕中的背景來自樣式資源庫。

XAML
<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 對應關係,並且不一定是依賴屬性。附加屬性的典型用途是允許子元素將屬性值報告給父元素,即使父元素和子元素不同時將該屬性作為類成員列表的一部分。一種主要情況是使子元素能夠告知父元素應如何在UI中呈現它們;有關示例,請參閱DockLeft有關詳細資訊,請參閱附加屬性概述

  • 元件開發人員或應用程式開發人員可能希望建立自己的依賴屬性,以便實現資料繫結或樣式支援之類的功能,或者實現對失效和值強制的支援。有關詳細資訊,請參閱自定義依賴屬性

  • 將依賴屬性視為公共屬性(可訪問)或至少由有權訪問例項的任何呼叫方發現的公共屬性。有關詳細資訊,請參閱依賴屬性的安全性