[UWP]依賴屬性1:概述

weixin_33816946發表於2018-01-25
原文:[UWP]依賴屬性1:概述

1. 概述

依賴屬性(DependencyProperty)是UWP的核心概念,它是有DependencyObject提供的一種特殊的屬性。由於UWP的幾乎所有UI元素都是整合於DependencyObject的FramewordElement,並且這些UI元素的幾乎所有屬性及它們出現在XAML中的幾乎所有屬性都是依賴屬性,所以可以說依賴屬性是專門為UI設計的屬性系統。
UWP的基本繼承關係

依賴屬性的定義:

/// <summary>
/// 獲取或設定Title的值
/// </summary>  
public string Title
{
    get { return (string)GetValue(TitleProperty); }
    set { SetValue(TitleProperty, value); }
}

/// <summary>
/// 標識 Title 依賴屬性。
/// </summary>
public static readonly DependencyProperty TitleProperty =
    DependencyProperty.Register("Title", typeof(string), typeof(MyPage), new PropertyMetadata(string.Empty));

如上述程式碼所示,和CLR屬性不同依賴屬性需要定義TitleProperty ,然後在屬性包裝器(Getter和Setter)中通過GetValue和SetValue函式操作屬性值。

2. 使用的場景

UWP的依賴屬性經過大幅簡化(相對於WPF),更關注它的核心功能:使用繫結,通過多個輸入計算屬性值,屬性值變化通知,節約記憶體使用。

2.1 繫結

通過屬性包裝器,依賴屬性可以像CLR屬性那樣使用,也可以在XAML中通過繫結來使用,這是CLR屬性不能提供的功能。

在XAML中使用:

<TextBlock x:Name="TextElement"
            Text="{Binding Title}" />

在程式碼中使用:

var binding = new Windows.UI.Xaml.Data.Binding();
binding.Path = new PropertyPath("Title");
TextElement.SetBinding(TextBlock.TextProperty, binding);

2.2 通過多個輸入計算屬性值

在UWP中依賴屬性通過多個輸入源計算屬性的值,從而使開發人員就避免了不必要的屬性設定值或者處理屬性值變更通知。以下列表從優先順序由高到低列出了依賴屬性的使用順序。

依賴屬性優先順序

  • 動畫值 正在執行的動畫,或具有 HoldEnd 行為的動畫。若要進行動畫處理,動畫的目標屬性必須是依賴項屬性。
  • 本地值 在程式碼中直接為物件例項設定的屬性值,或者在 XAML 中設定的屬性值。

    本地值可以通過呼叫ClearValue函式清除,從而使屬性值還原成預設值(以我的經驗來說,很少會用到)。

  • 模板屬性 如果在某個模板(來自 ControlTemplate 或 DataTemplate)中建立一個元素,該元素就會擁有這些模板屬性。
  • 樣式設定器 Style中的Setter。
  • 繼承值 元素可以從其在物件樹中的父級繼承依賴項屬性的值。譬如開發人員不必為每個TextBlock設定FontSize,只需要為父容器設定FontSize即可套用到父容器中的所有TextBlock上。
  • 預設值 不是指資料型別的預設值,是指PropertyMetadata中指定的預設值。在上面Title的例子中,預設值是string.Empty。

2.3 屬性值變化通知

使用依賴屬性,不必再實現INotifyPropertyChanged即可在屬性改變時通知UI更新。也可以在PropertyMeta中使用PropertyChangedCallback或DependencyObject.RegisterPropertyChangedCallback監視依賴屬性的屬性值改變。

2.4 節約記憶體使用

前面提到,UWP可以不必為所有值都設定值,UI元素的依賴屬性可以從樣式、繼承值、預設值等計算出實際值,並不需要分配記憶體;如果設定了本地值,這個本地值將儲存在HashTable中,之後從這個HashTable中讀取。這是一種以時間換空間的做法。
假設一個Control自身及所繼承的FrameworkElement等父型別中所有的屬性加起來大概50個,它的控制元件模板中大概有3個FrameworkElement,所有屬性都是double型別並且所有都不必要設定值,一個Control就可以節省50 * 3 * 8=1200位元組的記憶體空間。我做過的系統最多同時在UI上放了10W個Control,那麼就總共節省了大概100M記憶體。
這麼極端的情況也才節省這點記憶體,作用好像也沒那麼大(難道我算錯了?)。關於節約記憶體這點稍微瞭解下就好,有助於瞭解依賴屬性的原理,並且面試的時候有可能有幫助。

3 依賴屬性和CLR屬性之間的選擇

使用依賴屬性的情況

  • 基本上所有繼承DependencyObject的類中的屬性都應該是依賴屬性;
  • 需要使用Binding、Style或動畫設定值的屬性;
  • 需要監視屬性值變化通知;
  • 記憶體真的真的不夠用;

使用CLR屬性的情況

  • 集合屬性。在UWP中常見的集合屬性,只有ItemsControl的ItemsSource等少數幾個是依賴屬性,其它大部分都是CLR屬性,譬如Hub的Sections;
  • CPU效能敏感的場合。依賴屬性是用時間換空間的概念,假如需要頻繁讀寫而又不需要繫結,可以考慮使用CLR屬性;

4. 依賴屬性和執行緒

所有依賴屬性都只能在UI執行緒上使用,否則會拋異常(“應用程式呼叫一個已為另一執行緒整理的介面。”)。不過如果使用Async模式的話通常會迴避了執行緒的問題。

相關文章