揭秘依賴屬性
我在 SO 和其他網站上閱讀了很多關於依賴屬性的內容。但是,真的沒有找到一個很好的解釋,仍然很困惑。我同時使用 SL 和 WPF。就實現而言,它們在 SL 和 WPF 中是否有所不同?為什麼我們真的需要它們?它們是靜態的是否意味著它們的價值觀是共享的?MS 引入依賴屬性的原因是什麼?
答案就在名字本身,儘管“依賴”這個詞在軟體開發中充滿了意義,以至於它的含義並不是特別清楚。
依賴屬性是一個對象的屬性,其值依賴於其他對象。因此,例如:
- 罐子的
FontFamily屬性值TextBox(通常如此)取決於FontFamily其容器的屬性。如果更改容器上的屬性,則TextBox更改上的值。- a的
Text屬性值TextBox可以取決於綁定的數據源。當綁定屬性的值發生變化時,該Text屬性的值也會發生變化。- a的
Opacity屬性值Label可以取決於動畫情節提要,在常見的場景中,您設置了 UI 元素以淡入或淡出以響應某些事件。- 任何 UI 元素上各種屬性的值都取決於您應用到它們的樣式。
依賴背後的核心概念是,依賴的東西應該從它所依賴的東西中獲取屬性值。這就是為什麼依賴屬性被實現為一個 CLR 屬性,它的 getter 呼叫一個方法。
當
TextBox或渲染它的東西需要知道它FontFamily是什麼時,FontFamilygetter 呼叫該GetValue方法。該方法從容器、動畫、綁定等中查找值。這種方法有很多複雜性。例如,如果值是繼承的,它的工作方式與 WPF 在資源字典中查找樣式的方式非常相似:它在本地字典中查找值,如果沒有條目,則在其父字典中查找,並且一直如此,直到找到一個值或到達層次結構的頂部,在這種情況下,它使用預設值。
如果您查看依賴屬性的實現,就會發現。依賴對像有一個字典,它可能包含也可能不包含給定屬性的條目。該
GetValue方法從該字典中獲取值(這就是具有依賴屬性的對象可以具有覆蓋它們所繼承的本地值的方式),如果它沒有找到該值,它使用關於屬性的元資訊來確定在哪裡它應該看起來。由於該元資訊對於類中的每個對像都是相同的(即,
TextBox.Text對於每個對像都相同TextBox),因此儲存它的字典是該類的靜態屬性。所以當你看到這樣的程式碼時:
static Button() { // Register the property Button.IsDefaultProperty = DependencyProperty.Register("IsDefault", typeof(bool), typeof(Button), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnIsDefaultChanged))); }正在發生的事情是定義
IsDefault所有Button對象屬性的元資訊被添加到該字典中。當你看到這個:public bool IsDefault { get { return (bool)GetValue(Button.IsDefaultProperty); } set { SetValue(Button.IsDefaultProperty, value); } }您所看到的是基於該元資訊查找屬性值(來自本地字典、父對像或其他)的 getter 方法。
還記得我說過 getter 查找屬性值的第一個地方是對象的本地字典嗎?setter 中的
SetValue方法是如何將該條目添加到字典中(如果曾經呼叫過它,那麼只有當您通過顯式設置屬性來覆蓋依賴項時才會這樣做,即說“我希望它TextBox顯示文本Consolas而不考慮視窗中的其他控制項正在使用什麼。”)。我們從這種明顯複雜的系統中獲得的一個非常重要的好處是,對象的依賴屬性只有在設置時才會消耗記憶體。如果我創建 10,000 個
TextBox控制項並將它們添加到 aWindow中,則其中沒有一個實際上包含對FontFamily對象的引用。那是 10,000 個對象引用,我沒有為其分配記憶體,垃圾收集器也沒有檢查。事實上,如果 aTextBox有 100 個依賴屬性(它確實有),那麼無論何時創建 aTextBox,這都是 100 個支持欄位,您不會為其分配記憶體。依賴屬性僅在顯式設置時才會消耗記憶體。由於 UI 對像上的絕大多數屬性永遠不會被明確設置,因此這些是非常節省的。