自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Silverlight基礎(chǔ)屬性:依賴(lài)與附加

開(kāi)發(fā) 后端 前端
依賴(lài)屬性(Dependency Property)和附加屬性(Attached Property)這兩個(gè)算是Silverlight中非?;A(chǔ)的知識(shí),特別是CLR屬性,這個(gè)在DotNet編程中隨處可見(jiàn)。

作為微軟進(jìn)軍RIA領(lǐng)域的武器,Silverlight正在得到微軟的大力推廣,其***版本也在不久前的MIX10大會(huì)上發(fā)布,新版本不僅增多了50多項(xiàng)功能,同時(shí)也向我們呈現(xiàn)了各種開(kāi)發(fā)工具包。

在Silverlight中,依賴(lài)屬性(Dependency Property)和附加屬性(Attached Property)這兩個(gè)算是很基礎(chǔ)的知識(shí),下面我們著重分析這兩個(gè)屬性。

CLR屬性與依賴(lài)屬性

CLR屬性我們非常熟悉了,在DotNet編程中隨處可見(jiàn)。最簡(jiǎn)單最常見(jiàn)的屬性訪問(wèn)器就是直接操縱類(lèi)的私有成員,如下:

  1. public class Person{      
  2. private String _name;      
  3. public string Name      
  4. {          
  5. get { return _name; }         
  6. set { _name = value; }      
  7. }} 

C#3.0對(duì)這種常見(jiàn)的寫(xiě)法提供了“自動(dòng)屬性”這一特性,方便了偶等這些懶惰的碼農(nóng)。

  1. public class Person{      
  2. public string Name { get; set; }  

這兩種寫(xiě)法是等價(jià)的,都是需要設(shè)立一個(gè)實(shí)例級(jí)的私有變量作為屬性訪問(wèn)器的持久存儲(chǔ)。這對(duì)于我們非UI應(yīng)用來(lái)說(shuō)沒(méi)什么。因?yàn)?**,我們一般不會(huì)創(chuàng)建太多類(lèi)實(shí)例;第二,一個(gè)類(lèi)的屬性通常不會(huì)很多,加幾個(gè)私有變量不會(huì)增加系統(tǒng)負(fù)擔(dān)。但是這兩個(gè)理由對(duì)于UI應(yīng)用程序來(lái)說(shuō)恰恰不成立。

在很多UI應(yīng)用中,我們經(jīng)常會(huì)創(chuàng)建很多類(lèi)實(shí)例,成千上萬(wàn)個(gè)實(shí)例在UI系統(tǒng)中是很普遍的事情。同時(shí),UI類(lèi)通常會(huì)包含大量的屬性供設(shè)計(jì)人員使用,例如背景顏色,前景顏色,字體,邊距等等,這些屬性在絕大多數(shù)情況下會(huì)保持默認(rèn)值,如果為每個(gè)實(shí)例都建立這么多的私有變量來(lái)存儲(chǔ)UI屬性的值,勢(shì)必會(huì)造成極大的浪費(fèi),對(duì)系統(tǒng)負(fù)擔(dān)的開(kāi)銷(xiāo)也是不小。鑒于以上提到的問(wèn)題,設(shè)計(jì)一個(gè)高效的屬性存儲(chǔ)系統(tǒng)對(duì)于UI應(yīng)用程序的開(kāi)發(fā)是非常重要的。因此Silverlight引入了“依賴(lài)屬性(DependencyProperty)”。

采用鍵值對(duì)替代成員變量作為屬性?xún)?nèi)部存儲(chǔ)

傳統(tǒng)CLR屬性,一個(gè)屬性對(duì)應(yīng)一個(gè)私有變量,UI元素的屬性那么多,創(chuàng)建過(guò)多的私有變量不是一件簡(jiǎn)單的事情,況且大多數(shù)屬性只會(huì)用到默認(rèn)值。因此Silverlight使用鍵值對(duì)的形式來(lái)存放那些用戶(hù)顯式設(shè)置的屬性(稱(chēng)為L(zhǎng)ocal Value本地值),沒(méi)有設(shè)置的屬性就不存。那屬性的默認(rèn)值存放在哪?既然各個(gè)實(shí)例的默認(rèn)值都一樣(不然也不叫默認(rèn)值了),那么直接存放到靜態(tài)成員變量上就行了。這也就大大提高了存儲(chǔ)的效率。

注冊(cè)依賴(lài)屬性

既然依賴(lài)屬性采用鍵值對(duì)這樣的哈希結(jié)構(gòu)進(jìn)行存儲(chǔ),那么要獲取不同屬性的值,我們就必須使用不同的哈希鍵,否則就會(huì)讀取到其他屬性的值了。因此,當(dāng)我們?cè)谙騍ilverlight屬性系統(tǒng)注冊(cè)依賴(lài)屬性的時(shí)候,Silverlight會(huì)返回一個(gè)唯一的屬性標(biāo)識(shí)對(duì)象,類(lèi)型為DependencyProperty。我們以后就通過(guò)這個(gè)唯一標(biāo)識(shí)對(duì)象去訪問(wèn)依賴(lài)屬性的值。

由于這個(gè)唯一標(biāo)識(shí)符是所有類(lèi)實(shí)例都公用并且不會(huì)被修改的,因此我們通常將其保存到一個(gè)static readonly的成員變量中。DependencyProperty類(lèi)提供了兩個(gè)方法,一個(gè)是Register方法,用于注冊(cè)依賴(lài)屬性;另外一個(gè)是RegisterAttached,用于注冊(cè)附加屬性。

  1. public static DependencyProperty Register(string name,Type propertyType,Type ownerType,PropertyMetadata typeMetadata) 
  2.  

Register方法的簽名由幾部分組成,Name參數(shù)指明了依賴(lài)屬性使用的名稱(chēng),這個(gè)名字很重要,在定義控件Style和Template的時(shí)候,Setter的Property屬性填入的值就是注冊(cè)依賴(lài)屬性時(shí)使用的名稱(chēng);propertyType指明了依賴(lài)屬性實(shí)際的類(lèi)型,ownerType指明了是哪個(gè)類(lèi)注冊(cè)了此依賴(lài)屬性,***typeMetadata存放了一些依賴(lài)屬性的元信息,包括依賴(lài)屬性使用的默認(rèn)值,還有屬性值發(fā)生變更時(shí)的通知函數(shù)。 #p#

屬性的存取

和CLR屬性不同,依賴(lài)屬性不是直接對(duì)私有變量的操縱,而是通過(guò)GetValue和SetValue的方法來(lái)操作屬性值的。下面的代碼演示了為Ball控件設(shè)置一個(gè)Center的依賴(lài)屬性,并且在程序中讀取和修改此屬性的過(guò)程:

  1. public class Ball : Control{      
  2. public static readonly DependencyProperty CenterProperty =          
  3. DependencyProperty.Register("Center", typeof(Point), typeof(Ball), null);  
  4. }  
  5. public class BallApp{    public void RollBall(Ball ball)      
  6. {          
  7. Point curCenter = (Point)ball.GetValue(Ball.CenterProperty);  
  8. curCenter.X++;        // 注意對(duì)值類(lèi)型對(duì)象操作完畢之后一定要調(diào)用SetValue修改才能生效          
  9. ball.SetValue(Ball.CenterProperty, curCenter);      
  10. }} 

由于上述對(duì)依賴(lài)屬性的操作經(jīng)常需要涉及到類(lèi)型的轉(zhuǎn)換,比較麻煩,而傳統(tǒng)CLR屬性用起來(lái)和直接操縱普通變量一樣方便,因此通常在設(shè)計(jì)依賴(lài)屬性的時(shí)候,都會(huì)使用CLR屬性將其包裝起來(lái),我們稱(chēng)之為增強(qiáng)型的CLR屬性。

  1. public class Ball : Control{   
  2. public static readonly DependencyProperty CenterProperty =          
  3. DependencyProperty.Register("Center", typeof(Point), typeof(Ball), null);          
  4. public Point Center      
  5. { get { return (Point)GetValue(CenterProperty); }          
  6. set { SetValue(CenterProperty, value); }    }} 

按照約定,依賴(lài)屬性的名稱(chēng)通常是相應(yīng)CLR屬性名稱(chēng)后面加上個(gè)“Property”字符串。事實(shí)上,使用CLR包裝依賴(lài)屬性并不只是為了方便,很多依賴(lài)于CLR屬性作為基礎(chǔ)的工具或者子系統(tǒng)并不能直接訪問(wèn)依賴(lài)屬性,而只能通過(guò)CLR屬性去間接訪問(wèn)依賴(lài)屬性。

例如上面的例子中,假設(shè)我們并沒(méi)有設(shè)置一個(gè)Center的CLR屬性,那么以下的Xaml將會(huì)編譯失敗,因?yàn)閄aml解析器無(wú)法知道Ball類(lèi)有一個(gè)Center的依賴(lài)屬性(在Style中設(shè)置Center屬性值就可以編譯成功,因?yàn)镾tyle是動(dòng)態(tài)查找屬性的)。<Ball Center="2" />依賴(lài)屬性的尋值邏輯和值變更通知,上面提到的只是依賴(lài)屬性相比CLR屬性在存儲(chǔ)效率的不同,實(shí)際上,依賴(lài)屬性還有其他實(shí)用的特性。

尋值邏輯

CLR屬性在獲取值的時(shí)候是直接讀取成員變量值返回的,而依賴(lài)屬性在使用的時(shí)候是通過(guò)GetValue函數(shù)的調(diào)用來(lái)獲取屬性的值。實(shí)際上,GetValue內(nèi)部做的事情可不止是簡(jiǎn)單的讀取字典里頭存放的值。他還有尋值邏輯。如下圖所示:

當(dāng)你調(diào)用GetValue去讀取一個(gè)依賴(lài)屬性的值的時(shí)候,Silverlight的屬性系統(tǒng)會(huì)首先從動(dòng)畫(huà)系統(tǒng)中查找當(dāng)前是否有作用在此依賴(lài)屬性上的動(dòng)畫(huà),如果有,則返回此動(dòng)畫(huà)值。從這里也可以看出,依賴(lài)屬性是Silverlight實(shí)現(xiàn)動(dòng)畫(huà)機(jī)制的基礎(chǔ)。注意,如果動(dòng)畫(huà)已經(jīng)停止了,并且沒(méi)有設(shè)置FillBehavior=HoldEnd的話(huà),那么Silverlight就不會(huì)返回此動(dòng)畫(huà)值。

如果讀不到動(dòng)畫(huà)值,那么Silverlight就會(huì)嘗試讀取本地值。本地值有幾種類(lèi)型,一種是用戶(hù)通過(guò)代碼或者Xaml直接設(shè)定的值。一種是通過(guò)資源綁定得到的值,***一種是通過(guò)數(shù)據(jù)綁定得到的值。這些都被視為本地值。

  1. <StackPanel x:Name="LayoutRoot">      
  2. <StackPanel.Resources>          
  3. <System:String x:Key="TextBlockResource">資源數(shù)據(jù)綁定文本  
  4. </System:String>    </StackPanel.Resources>      
  5. <TextBlock Text="{Binding Source={StaticResource TextBlockResource}}" />      
  6. <TextBlock x:Name="DataBindingElement" Text="{Binding ElementName}" /> 
  7. </StackPanel> 

如果還是讀取不到,那么就繼續(xù)嘗試讀取控件模板和樣式中設(shè)置的值。如果所有這些值都讀取失敗,那么Silverlight屬性系統(tǒng)就會(huì)返回該依賴(lài)屬性的默認(rèn)值。當(dāng)我們注冊(cè)依賴(lài)屬性的時(shí)候,可以傳入一個(gè)PropertyMetaData對(duì)象,這個(gè)對(duì)象包含了此依賴(lài)屬性的默認(rèn)值和值變更通知回調(diào)函數(shù)。如果注冊(cè)的時(shí)候沒(méi)有傳入默認(rèn)值,則對(duì)于引用類(lèi)型的依賴(lài)屬性,返回null,對(duì)于字符串,返回String.Empty,對(duì)于值類(lèi)型,則返回一個(gè)以默認(rèn)值初始化的實(shí)例。這里需要對(duì)集合類(lèi)型特別注意,由于通過(guò)PropertyMetaData傳入的默認(rèn)值是所有類(lèi)實(shí)例共享的,因此,一定要在類(lèi)構(gòu)造函數(shù)中顯式傳入集合的實(shí)例。

  1. public class GameRoom : Control{     
  2.  public List<Ball> Balls      
  3. {          
  4. get { return (List<Ball>)GetValue(BallsProperty);   
  5. }          
  6. set { SetValue(BallsProperty, value); }      
  7. }     
  8.  public static readonly DependencyProperty BallsProperty =          
  9. DependencyProperty.Register("Balls", typeof(List<Ball>), typeof(GameRoom), null);   
  10.    public GameRoom()    {          
  11. Balls = new List<Ball>();    }} 

可能正是因?yàn)镾ilverlight的依賴(lài)屬性在獲取值的時(shí)候需要從多個(gè)地方去讀取值,而不是像CLR屬性一樣,直接從成員變量中讀取值,所以才被稱(chēng)之為“依賴(lài)”屬性吧。#p#

值變更通知

屬性值的變更通知我們并不陌生。我們?cè)贒otNet中實(shí)現(xiàn)的時(shí)候,一般是讓類(lèi)實(shí)現(xiàn)INotifyPropertyChanged接口。在UI系統(tǒng)中,值變更通知是經(jīng)常需要用到的。數(shù)據(jù)源一旦變更,所有相應(yīng)的UI元素的值都要相應(yīng)的做出調(diào)整。Silverlight的依賴(lài)屬性對(duì)此有內(nèi)置的支持。只要你在綁定時(shí)使用依賴(lài)屬性,那么當(dāng)依賴(lài)屬性值發(fā)生變更的時(shí)候,所有綁定的地方的值都會(huì)同步更新。而且,依賴(lài)屬性也提供了一個(gè)值變更通知函數(shù)(在注冊(cè)依賴(lài)屬性時(shí)通過(guò)PropertyMetaData傳入),你可以自定義一個(gè)函數(shù)來(lái)控制值變更時(shí)需要執(zhí)行的操作。

  1. public class Ball : Control{      
  2. public static readonly DependencyProperty   
  3.  
  4. CenterProperty=DependencyProperty.Register("Center", typeof(Point), typeof(Ball), new PropertyMetadata(OnCenterChanged));  
  5.     public Point Center    {          
  6. get { return (Point)GetValue(CenterProperty);   
  7. }         
  8.  set { SetValue(CenterProperty, value); }      
  9. }      
  10. private static void OnCenterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)      
  11. {         
  12.  Ball ball = d as Ball;        // 獲取新的球心         
  13.  Point newCenter = (Point)e.NewValue;     // Silverlight的附加屬性(Attached Property)  

全局的依賴(lài)屬性

剛才提到的依賴(lài)屬性和CLR屬性一樣都是服務(wù)于某一個(gè)類(lèi)的。只不過(guò)將屬性改造得存儲(chǔ)上更有效率,使用上更加強(qiáng)大。在Silverlight中還有一種特殊的依賴(lài)屬性,這種依賴(lài)屬性并不只是服務(wù)于某個(gè)特定的類(lèi),而是服務(wù)于全局,這就是附加屬性。從名字上也可以看出來(lái),附加屬性是在某個(gè)類(lèi)里面注冊(cè),然后可以被其他類(lèi)所使用。什么情況下需要使用附加屬性呢?舉Canvas類(lèi)的ZIndex屬性作為例子。容器類(lèi)在疊加子控件的時(shí)候,需要考慮哪個(gè)控件放置在最上面,那個(gè)放在下面。

那么容器類(lèi)怎么知道子控件的疊放順序呢?最不動(dòng)腦子的設(shè)計(jì)就是為所有的控件都添加一個(gè)ZIndex的屬性,屬性的值代表疊放的順序。但這樣的后果就是,如果我這個(gè)控件不參與布局,那多這個(gè)屬性就會(huì)顯得很浪費(fèi)。所以比較理想的設(shè)計(jì)是,需要用到這個(gè)屬性的時(shí)候就有這個(gè)屬性,不需要的時(shí)候就沒(méi)有這個(gè)屬性的負(fù)擔(dān)。附加屬性的出現(xiàn)就是為了解決這樣的問(wèn)題。一旦控件需要某個(gè)屬性的時(shí)候,我們可以把這個(gè)屬性附加到這個(gè)控件類(lèi)上。注冊(cè)附加屬性和依賴(lài)屬性差不多,只不過(guò)函數(shù)名為RegisterAttached。這個(gè)就不多說(shuō)了。

什么時(shí)候應(yīng)該用到依賴(lài)屬性

既然依賴(lài)屬性那么高效,而且那么強(qiáng)大,那么我們是不是應(yīng)該保持使用依賴(lài)屬性的習(xí)慣呢?事實(shí)上,任何好處都是有代價(jià)的。Silverlight的依賴(lài)屬性在訪問(wèn)效率上并不如直接訪問(wèn)成員變量那么高效。因此,對(duì)于那些比較簡(jiǎn)單而訪問(wèn)頻率又非常高的屬性,建議還是使用傳統(tǒng)的CLR屬性去實(shí)現(xiàn)。

【編輯推薦】

  1. 簡(jiǎn)單Silverlight應(yīng)用程序五步走 
  2. Silverlight WCF服務(wù)正確組建方法淺談
  3. Silverlight調(diào)用WCF出現(xiàn)異常解決方案
  4. 細(xì)數(shù)2009年Silverlight十大流行應(yīng)用
  5. 為你揭開(kāi)Silverlight代碼安全性秘密

 

責(zé)任編輯:王曉東 來(lái)源: 博客園
相關(guān)推薦

2010-01-04 18:26:11

Silverlight

2009-12-23 11:24:42

WCF附加屬性

2009-12-29 10:22:34

WPF附加屬性

2009-12-30 13:59:58

Silverlight

2015-09-17 13:42:26

2009-08-03 13:53:30

C#調(diào)用Excel

2009-08-06 09:37:09

Silverlight

2010-09-01 14:41:35

paddingline-heightCSS

2010-02-22 17:34:39

WCF依賴(lài)屬性

2023-09-15 11:49:33

wpf依賴(lài)屬性

2009-03-19 09:01:53

Silverlight微軟Flash

2009-08-21 14:07:05

Flex與Silver

2009-05-13 15:46:30

FlashSilverlight大比拼

2010-03-17 09:22:06

FlashSilverlight

2016-03-30 11:54:20

2009-11-17 10:47:14

Silverlight

2023-04-28 09:05:20

魔方基礎(chǔ)流程

2009-12-22 14:31:27

WCF序列化依賴(lài)屬性

2009-12-25 14:18:03

WPF依賴(lài)屬性

2010-01-04 16:06:34

Silverlight
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)