天天看點

初步了解WPF依賴屬性

一 依賴屬性

    在WPF庫實作中,依賴屬性使用普通的C#屬性進行了包裝,使得我們可以通過和以前一樣的方式來使用依賴屬性。但必須明确,在WPF中我們大多數都在使用依賴屬性,而不是使用屬性。依賴屬性重要性在于,在WPF核心特性,如動畫、資料綁定以及樣式中都需要使用到依賴屬性。WPF中的依賴屬性主要有以下三個優點:

    依賴屬性加入了屬性變化通知、限制、驗證等功能。這樣可以使我們更友善地實作應用,同時大大減少了代碼量。許多之前需要寫很多代碼才能實作的功能,在WPF中可以輕松實作。

    節約記憶體:在WinForm中,每個UI控件的屬性都賦予了初始值,這樣每個相同的控件在記憶體中都會儲存一份初始值。而WPF依賴屬性很好地解決了這個問題,它内部實作使用哈希表存儲機制,對多個相同控件的相同屬性的值都隻儲存一份。

    支援多種提供對象:可以通過多種方式來設定依賴屬性的值。可以配合表達式、樣式和綁定來對依賴屬性設定值。

二 如何自己定義一個依賴屬性

    在C#屬性定義的基礎上;

    讓依賴屬性的所在類型繼承自DependencyObject類;

    使用public static 聲明一個DependencyProperty的變量,該變量就是真正的依賴屬性;

    在類型的靜态構造函數中通過Register方法完成依賴屬性的中繼資料注冊;

    提供一個依賴屬性的包裝屬性,通過這個屬性來完成對依賴屬性的讀寫操作;

    依賴屬性是通過調用DependencyObject的GetValue和SetValue來對依賴屬性進行讀寫的。它使用哈希表來進行存儲的,對應的Key就是屬性的HashCode值,而值(Value)則是注冊的DependencyPropery;而C#中的屬性是類私有字段的封裝,可以通過對該字段進行操作來對屬性進行讀寫。總結為:屬性是字段的包裝,WPF中使用屬性對依賴屬性進行包裝。

三 依賴屬性優先級

    按從高到低排序:

1 屬性系統強制轉換。強制轉換和動畫在本 SDK 中都作用于稱為“基值”的值。便于動畫不受别的設定影響。

2 活動動畫或具有 Hold 行為的動畫。為了獲得任何實用效果,屬性的動畫必須優先于基(未動畫)值,即使該值是在本地設定的情況下也将如此。

3 本地值。本地值可以通過“包裝”屬性 (Property) 的便利性進行設定,這也相當于在 XAML 中設定 Attribute 或 Property 元素,或者使用特定執行個體的屬性調用 SetValue API。如果您使用綁定或資源來設定本地值,則每個值都按照直接設定值的優先級順序來應用。

4 TemplatedParent 模闆屬性。如果元素是作為模闆(ControlTemplate 或 DataTemplate)的一部分建立的,則具有 TemplatedParent。在模闆中,按以下優先級順序應用:

    1 來自 TemplatedParent 模闆的觸發器。

    2 TemplatedParent 模闆中的屬性 (Property) 集。(通常通過 XAML 屬性 (Attribute) 進行設定。)

5 隐式樣式。僅應用于Style屬性。Style屬性是由任何樣式資源通過與其類型比對的鍵來填充的。該樣式資源必須存在于頁面或應用程式中;查找隐式樣式資源不會進入到主題中。

6 樣式觸發器。來自頁面或應用程式上的樣式中的觸發器。(這些樣式可以是顯式或隐式樣式,但不是來自優先級較低的預設樣式。)

7 模闆觸發器。來自樣式中的模闆或者直接應用的模闆的任何觸發器。

8 樣式 Setter。來自頁面或應用程式的樣式中的 Setter 的值。

9 預設(主題)樣式。在預設樣式中,按以下優先級順序應用:

    1 主題樣式中的活動觸發器。

    2 主題樣式中的 Setter。

10 繼承。有幾個依賴項屬性從父元素向子元素繼承值,是以不需要在應用程式中的每個元素上專門設定這些屬性。

11 來自依賴項屬性中繼資料的預設值。任何給定的依賴項屬性都具有一個預設值,它由該特定屬性的屬性系統注冊來确定。而且,繼承依賴項屬性的派生類具有按照類型重寫該中繼資料(包括預設值)的選項。因為繼承是在預設值之前檢查的,是以對于繼承的屬性,父元素的預設值優先于子元素。是以,如果任何地方都沒有設定可繼承的屬性,将使用在根元素或父元素中指定的預設值,而不是子元素的預設值。

四 一個簡單執行個體

初步了解WPF依賴屬性
<Page
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Grid>  
    <Button x:Name="myButton" Background="Green" Width="400" Height="300">
            <Button.Style>
                <Style TargetType="{x:Type Button}">
                    <Setter Property="Background" Value="Yellow"/>
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="Red" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </Button.Style>
            Click Me 
        </Button>
  </Grid>
</Page>
           

    代碼在三個地方設定了按鈕的顔色;按鈕最終為綠色;