天天看點

[UWP]依賴屬性1:概述1. 概述2. 使用的場景3 依賴屬性和CLR屬性之間的選擇4. 依賴屬性和線程

依賴屬性(DependencyProperty)是UWP的核心概念,它是有DependencyObject提供的一種特殊的屬性。由于UWP的幾乎所有UI元素都是內建于DependencyObject的FramewordElement,并且這些UI元素的幾乎所有屬性及它們出現在XAML中的幾乎所有屬性都是依賴屬性,是以可以說依賴屬性是專門為UI設計的屬性系統。

依賴屬性的定義:

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

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

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

在XAML中使用:

在代碼中使用:

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

動畫值 正在運作的動畫,或具有 HoldEnd 行為的動畫。若要進行動畫處理,動畫的目标屬性必須是依賴項屬性。

本地值 在代碼中直接為對象執行個體設定的屬性值,或者在 XAML 中設定的屬性值。

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

模闆屬性 如果在某個模闆(來自 ControlTemplate 或 DataTemplate)中建立一個元素,該元素就會擁有這些模闆屬性。

樣式設定器 Style中的Setter。

繼承值 元素可以從其在對象樹中的父級繼承依賴項屬性的值。譬如開發人員不必為每個TextBlock設定FontSize,隻需要為父容器設定FontSize即可套用到父容器中的所有TextBlock上。

預設值 不是指資料類型的預設值,是指PropertyMetadata中指定的預設值。在上面Title的例子中,預設值是string.Empty。

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

前面提到,UWP可以不必為所有值都設定值,UI元素的依賴屬性可以從樣式、繼承值、預設值等計算出實際值,并不需要配置設定記憶體;如果設定了本地值,這個本地值将存儲在HashTable中,之後從這個HashTable中讀取。這是一種以時間換空間的做法。

假設一個Control自身及所繼承的FrameworkElement等父類型中所有的屬性加起來大概50個,它的控件模闆中大概有3個FrameworkElement,所有屬性都是double類型并且所有都不必要設定值,一個Control就可以節省50 * 3 * 8=1200位元組的記憶體空間。我做過的系統最多同時在UI上放了10W個Control,那麼就總共節省了大概100M記憶體。

這麼極端的情況也才節省這點記憶體,作用好像也沒那麼大(難道我算錯了?)。關于節約記憶體這點稍微了解下就好,有助于了解依賴屬性的原理,并且面試的時候有可能有幫助。

使用依賴屬性的情況

基本上所有繼承DependencyObject的類中的屬性都應該是依賴屬性;

需要使用Binding、Style或動畫設定值的屬性;

需要監視屬性值變化通知;

記憶體真的真的不夠用;

使用CLR屬性的情況

集合屬性。在UWP中常見的集合屬性,隻有ItemsControl的ItemsSource等少數幾個是依賴屬性,其它大部分都是CLR屬性,譬如Hub的Sections;

CPU性能敏感的場合。依賴屬性是用時間換空間的概念,假如需要頻繁讀寫而又不需要綁定,可以考慮使用CLR屬性;

所有依賴屬性都隻能在UI線程上使用,否則會抛異常(“應用程式調用一個已為另一線程整理的接口。”)。不過如果使用Async模式的話通常會回避了線程的問題。