依賴屬性就是一種可以自己沒有值,并能通過使用Binding從數(shù)據(jù)源獲得值(依賴在別人身上)的屬性。擁有依賴屬性的對象稱為“依賴對象”。
WPF開發(fā)中,必須使用依賴對象作為依賴屬性的宿主,使二者結(jié)合起來。依賴對象的概念被DependencyObject類所實(shí)現(xiàn),依賴屬性的概念則由DependencyProperty類所實(shí)現(xiàn)
從這棵繼承樹上可以看出,WPF的所有UI空間都是依賴對象。
看最簡單的依賴屬性
class Student : DependencyObject { public string Name { get { return ( string )GetValue(NameProperty); } set { SetValue(NameProperty, value); } } public static readonly DependencyProperty NameProperty = DependencyProperty.Register( " Name " , typeof ( string ), typeof (Student)); }
實(shí)例并非使用new操作符得到而是使用DependencyProperty.Register方法生成。
現(xiàn)在我們使用的Register方法是參數(shù)最少,最簡單的一個(gè)重載,我們來分析一下
- 第一個(gè)參數(shù)為string類型,表示指明以哪個(gè)CLR屬性作為這個(gè)依賴屬性的包裝器。就是代碼
public string Name { get { return ( string )GetValue(NameProperty); } set { SetValue(NameProperty, value); } }
- 第二個(gè)參數(shù)指明此依賴屬性用來存儲(chǔ)什么樣的值。
- 第三個(gè)參數(shù)用來指明此依賴屬性的宿主是什么類型,或者說DependencyProperty.Register方法要將這個(gè)依賴屬性注冊到哪個(gè)類型上。
注意 :1.依賴屬性包裝器是一個(gè)CLR屬性,并不是依賴屬性,沒有包裝器,依賴屬性依舊存在。
???????? 2.既然沒有包裝器依賴屬性也存在,那么包裝器是干什么用的呢?包裝器的作用是以“實(shí)例屬性”的形式向外界暴露依賴屬性,這樣,一個(gè)依賴屬性才能成為數(shù)據(jù)源的一個(gè)Path。
???????? 3.注冊依賴屬性時(shí)使用的第二個(gè)參數(shù)是一個(gè)數(shù)據(jù)類型,這個(gè)數(shù)據(jù)類型也是包裝器的數(shù)據(jù)類型。
請看例子
< Window x:Class ="DependencyPropertySample.MainWindow" xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml" Title ="MainWindow" Height ="350" Width ="525" > < StackPanel > < TextBox x:Name ="textbox1" BorderBrush ="Black" Margin ="5" /> < TextBox x:Name ="textbox2" BorderBrush ="Black" Margin ="5" /> < Button Content ="OK" Margin ="5" Click ="Button_Click" /> </ StackPanel > </ Window >
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Button_Click( object sender, RoutedEventArgs e) { Student stu = new Student(); stu.SetValue(Student.NameProperty, textbox1.Text); textbox2.Text = ( string )stu.GetValue(Student.NameProperty); } }
當(dāng)?shù)谝淮慰吹竭@個(gè)例子的時(shí)候,也許會(huì)有點(diǎn)百思不得其解的感覺——依賴屬性不是一個(gè)Static對象么?哪怕有1000個(gè)Student實(shí)例,依賴屬性只有一個(gè)啊,那么SetValue把值存儲(chǔ)到哪里去了?GetValue又從哪里讀取值?并且,依賴屬性不是一個(gè)只讀的嗎?怎么可以寫入值呢? 其實(shí)這個(gè)問題直指依賴屬性機(jī)制的核心,我們過一會(huì)再討論。
還要注意一點(diǎn),盡管student類沒有實(shí)現(xiàn)INotifyPropertyChange接口,當(dāng)屬性的值發(fā)生改變時(shí)與之關(guān)聯(lián)的Binding對象依然可以得到通知,依賴屬性默認(rèn)帶有這樣的功能,天生就是合格的數(shù)據(jù)源。
使用vs2010有一個(gè)小技巧,生成依賴屬性可以使用代碼段propdp,DependencyProperty.Register帶4個(gè)參數(shù),第四個(gè)參數(shù)的類型是PropertyMetadata類,作用是給依賴屬性的DefaultMetadata屬性賦值。顧名思義,DefaultMetadata的作用就是向依賴屬性的調(diào)用者提供一些基本信息,這些信息包括:
- CoerceValueCallback :依賴屬性的值被強(qiáng)制改變時(shí)此委托會(huì)被調(diào)用,此委托可關(guān)聯(lián)一個(gè)函數(shù)。
- DefaultValue :依賴屬性未被顯示賦值時(shí),若讀取之則獲得此默認(rèn)值,不設(shè)置此值會(huì)拋出異常。
- IsSealed :控制PropertyMetadata的屬性值是否可以更改,默認(rèn)值為true。
- PropertyChangeCallback :依賴屬性的值被改變之后此委托會(huì)被調(diào)用,此委托可關(guān)聯(lián)一個(gè)函數(shù)。
注意:依賴屬性的DefaultMetadata只能通過Register方法的第四個(gè)參數(shù)驚醒賦值,而且一旦賦值就不能改變。如果想用新的PropertyMetadata替換這個(gè)默認(rèn)的Metadata,需要使用DependencyProperty.OverrideMetadata方法。
下面我們來解決剛才的紅色問題。
首先值存到什么地方去了?
創(chuàng)建一個(gè)DependencyProperty實(shí)例并用它的CLR屬性名和宿主類型名生成hash code,最后把hash code和DependencyProperty實(shí)例作為Key-Value對存入全局的,名為PropertyFormName的Hashtable中。
。。。(我認(rèn)為書上寫的太深?yuàn)W啦,想要深究的同學(xué)可以參考《深入淺出WPF》)
初學(xué)者不必深究,那就是使用了static和readonly是為了保證DependencyProperty的索引值唯一。真正的值是存在一個(gè)Hashtable中的,當(dāng)然可讀可寫啦。
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
