WPF相依屬性與附加屬性

by Vivid 10. 八月 2011 01:00

NET Magazine國際中文電子雜誌

作者:許薰尹 精誠資訊恆逸教育訓練中心 資深講師

審 稿:張智凱

文章編號:N110811501

出刊日期:2011/8/10

 

為了簡化WPF應用程式的設計,WPF內建一個屬性系統用來管理物件的屬性值。WPF的屬性和一般.NET屬性不太相同,本文將介紹WPF中的相依屬性(Depedency Property)和附加屬性(Attached Property)。

一般.NET屬性的定義方式,會在類別中宣告一個private欄位(稱為backing field)來存放屬性值,然後再定義一個屬性透過屬性的set、set存取子來設定或讀取backing field的值,這種標準的.NET屬性稱為CLR屬性,例如以下有一個MyClass類別,包含一個MyProperty屬性。

public class MyClass {     
      private int myVar;
      public int MyProperty {
          get { return myVar; }
          set { myVar = value; }
      }       
  }

WPF提供一種新的屬性稱為相依屬性(Dependency Property),屬性的值不一定是儲存在一個簡單的欄位(Field)。WPF的屬性系統會自動管理為相依屬性。

相依屬性(Dependency Property)

相依屬性有一個特色,您可以在父項目設定好屬性值,子項目便會自動套用此屬性值。如此只需要在父項目做統一的設定,例如以下有一個StackPanel項目,其中包含兩個Label,在StackPanel之中設定Opacity屬性為0.1,因為相依屬性具有繼承關係,因此StackPanel之中的兩個Label就自動套用StackPanel Opacity屬性的設定值:

<StackPanel  Opacity="0.1"  Height="100" HorizontalAlignment="Left" Margin="128,78,0,0" Name="stackPanel1" VerticalAlignment="Top" Width="200" >
         <Label Content="Label" Height="28" Name="label1" />
            <Label  Content="Label" Height="28" Name="label2" />
</StackPanel>

圖一是StackPanel、Label與WPF屬性系統的繼承關係圖。

clip_image002

圖 1:相依屬性會自動繼承

自訂相依屬性

大部分的情況下,撰寫WPF應用程式時,您並不太有機會自訂相依屬性。但若想要設計自訂控制項,那麼就會有自訂相依屬性的需求。底下範例程式碼為一個WPF視窗自訂一個名為MyCustomProperty的相依屬性,此自訂屬性與WPF屬性系統的架構圖請參考圖2。

public partial class MyCustomDep : Window {
        public MyCustomDep ( ) {
            InitializeComponent ( );
        }
        public static readonly DependencyProperty MyCustomProperty =
        DependencyProperty.Register ( "MyCustom" , typeof ( string ) ,
        typeof ( MyCustomDep ) , new FrameworkPropertyMetadata ( ) );

        public string MyCustom {
            get { return ( string ) GetValue ( MyCustomProperty ); }
            set { SetValue ( MyCustomProperty , value ); }
        }
        private void button1_Click ( object sender , RoutedEventArgs e ) {
            this.MyCustom = DateTime.Now.ToString ( );
            MessageBox.Show ( this.MyCustom );
        }
    }

剖析上列程式,MyCustomDep是一個WPF Window,只有繼承自DepenendyObject的類別才能夠定義相依屬性,這樣才能和WPF的屬性系統進行互動:

public partial class MyCustomDep : Window {

}

類別中必需為相依屬性定義一型別為DependencyProperty的個欄位(Field),記錄Depedency Property Identifier的參考,且宣告時必需為public static readonly。宣告屬性時,屬性的名稱最後應該以Property字串結尾,如本例的MyCustomProperty。最後叫用DependencyProperty.Register方法向WPF屬性系統註冊相依屬性,這個方法會回傳Depedency Property Identifier。

public static readonly DependencyProperty MyCustomProperty =

DependencyProperty.Register ( "MyCustom" , typeof ( string ) ,

typeof ( MyCustomDep ) , new FrameworkPropertyMetadata ( ) );

Register方法的第一個參數代表相依屬性的名稱,但去掉結尾的Property字串;第二個參數相依屬性的型別;第三個參數是宣告此相依屬性的型別;第四個參數是一個FrameworkPropertyMetadata物件。向WPF屬性系統註冊相依屬性時可以利用FrameworkPropertyMetadata物件,利用它的屬性來告知WPF如何管理相依屬性,例如設定預設值,或指定屬性變更時的回呼函式。

clip_image004

圖 2:自訂相依屬性架構圖

若要存取相依屬性的值可透過DepedencyObject的GetValue與SetValue方法。你也可以為相依屬性定義一個CLR屬性包裝程式(如圖2標示的Wrapper),這樣使用相依屬性時語法就跟傳統.NET CLR屬性類似。CLR包裝程式的名稱應該和相依屬性名稱一樣(去掉結尾的Property字串),並在get、set存取子中利用DepedencyObject的GetValue與SetValue方法來操作屬性。而在WPF內部,這些包裝程式都會被忽略,WPF會直接叫用GetValue與SetValue方法,因此最好不要在get、set方法中撰寫其它的程式碼。

public string MyCustom {
            get { return ( string ) GetValue ( MyCustomProperty ); }
            set { SetValue ( MyCustomProperty , value ); }
}

附加屬性(Attached Properties)

附加屬性(Attached Properties) 是一種特殊型式的相依屬性,通常它在某個類別中定義,但卻是在其它類別中使用,你可以把它當做是一種全域屬性,可以在任何物件設定。附加屬性和相依屬性不太相同,你不需要為附加屬性顯露一個傳統的.NEET屬性包裝程式(Wrapper),不必繼承自DependencyObject類別。屬性的值是儲存在你附加的項目上,而不是顯露附加屬性的項目上。例如DockPanel中包含一個Button設定DockPanel. Dock為Top,因此Button會停駐在DockPanel的上方。DockPanel的Dock是一個附加屬性,但屬性是在Button上使用,而不是定義Dock屬性的DockPanel控制項上。

<DockPanel Name = "dockPanel1" LastChildFill = "False">

<Button Content = "Button" Height = "23" Name = "button1" Width = "75" DockPanel.Dock = "Top" />

</DockPanel>

實際上DockPanel實作了GetDock與SetDock方法,它會呼叫套用附加屬性的Button類別之GetValue與SetValue方法(定義在DependencyObject),參考圖3所示。

clip_image006

圖 3:DockPanel Dock附加屬性結構

附加屬性設定的語法為:

宣告的類別.屬性名稱

不過,附加屬性不是設定了就會有作用,例如以下範例,Button1是DockPanel第一層的子項目,設定Dock屬性有作用,但Button2則是位於StackPanel下,設定了Dock屬性並沒有作用:

<DockPanel Name = "dockPanel1" LastChildFill = "False" >
        <Button Content = "Button1" Height = "23" Name = "button1" Width = "75"
                DockPanel.Dock = "Bottom"
                />
        <StackPanel Height = "100"  Width = "200" Orientation = "Vertical">
            <Button Content = "Button2" Height = "23" Name = "button2" Width = "75"
                     DockPanel.Dock = "Bottom" />
        </StackPanel>
    </DockPanel>

此範例程式在開發工具呈現的結果,參考圖4所示。

clip_image008

圖 4:套用附加屬性

使用附加屬性

附加屬性不像一般.NET CLR屬性有包裝函式能夠存取附加屬性值,因此,宣告附加屬性的類別別必需實作「Get開頭+屬性名稱」與「Set開頭+屬性名稱」的方法以便於從程式中使用附加屬性,例如以下範例,使用DockPanel的GetDock方法讀取附加 button1的Dock屬性,然後將它設定為Dock.Top:

MessageBox.Show ( DockPanel.GetDock ( button1 ).ToString() );

DockPanel.SetDock ( button1 , Dock.Top );

使用FrameworkPropertyMetadata類別設計附加屬性

附加屬性是由XAML定義的,不是透過WPF,因此不必繼承自DependencyProperty。以下範例在自訂的MyDataClass類別定義附加屬性,定義附加屬性的類別必需繼承自DependencyObject類別:

class MyDataClass : DependencyObject {

}

若要定義附加屬性,屬性的名稱要遵循WPF慣例,以Property字串結尾,然後利用Dependency.RegisterAttached方法來定義。若要為附加屬性設定預設值,可以在註冊時利用FrameworkPropertyMetadata類別,RegisterAttached方法的第一個參數代表附加屬性的名稱,本範例為IsValid;第二個參數為附加屬性的型別,本範例為bool;第三個參數為擁有此附加屬性的型別,本範例為MyDataClass;最後一個參數代表一個PropertyMetadata物件,透過它將附加屬性的初始值設定為true:

DependencyProperty.RegisterAttached ( "IsValid" , typeof ( bool ) , typeof ( MyDataClass ),
new PropertyMetadata(true));

設計Get方法

你必需為附加屬性定義一個Get方法(稱Get 存取子),傳入一個輸入參數,表示使用此附加屬性的物件實體,以本例而言,便是UIElement,表示你只能在UIElement套用此附加屬性。Get方法的回傳值型別必須和RegisterAttached方法第二個參數的型別一致,以本例而言型別為bool型別。

public static bool GetIsValid ( UIElement target ) {

return ( bool ) target.GetValue ( IsValidProperty );

}

設計Set方法

你必需為附加屬性定義一個Set方法(稱Set 存取子),傳入兩個參數:第一個參數代表能夠使使用此附加屬性的型別;第二個參數代表附加屬性的值,因此此參數的型別必需和RegisterAttached方法第二個參數的型別一致。

public static void SetIsValid ( UIElement target , bool value ) {

target.SetValue ( IsValidProperty , value );

}

使用附加屬性

若要使用附加屬性參考以下範例, 在TextBox中直接套用附加屬性:

<Window x:Class = "DepProp.UseCustomProperty"
        xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
        Title = "UseCustomProperty" Height="300" Width="300"
        xmlns:local = "clr-namespace:DepProp" >
    <Grid>
        <TextBox
           local:MyDataClass.IsValid = "True"
            Height = "23" HorizontalAlignment = "Left" Margin = "10,10,0,0" Name = "textBox1" VerticalAlignment = "Top" Width = "120" />
    </Grid>
</Window>

實作附加行為(Attatched Behavior)

你可以為附加屬性設計附加行為(Attatched Behavior),例如變更外觀、拖曳或資料驗證動作。我們可以使用PropertyMetadata類別來為使用附加屬性的項目加上事件回呼函式,以便在屬性值變動時,進行一些額外的處理作業。例如以下範例程式碼,在註冊附加屬性時第四個參數傳入一個PropertyMetadata物件,將IsValid附加屬性初始值設定為false,然後設定PropertyChangedCallback委派指向OnIsValidChanged方法:

public static readonly DependencyProperty IsValidProperty
            = DependencyProperty.RegisterAttached ( "IsValid" , typeof ( bool ) , typeof ( MyDataClass ) ,
            new PropertyMetadata ( false , OnIsValidChanged ) );

本例中的OnIsValidChanged方法實作的行為是:當IsValid屬性的值為true時,便將套用附加屬性的TextBox的外框變成紅色,框線粗細設定為5:

public static void OnIsValidChanged ( DependencyObject source , DependencyPropertyChangedEventArgs e ) {
            if ( ( bool ) e.NewValue == true ) {
                TextBox txt = ( TextBox ) source;
                txt.BorderBrush = Brushes.Red;
                txt.BorderThickness = new Thickness ( 5 );
              
            }
}

總結

相依屬性的核心是DependencyProperty與DependencyObject類別。DependencyProperty類別的實體稱為Dependency Property Identifier,代表特定相依屬性的特性。DependencyObject物件包含所有和WPF屬性系統互動的架構。

 
   

Tags:

NET 開發 | WPF | 許薰尹Vivid Hsu | .NET Magazine國際中文電子雜誌

評論 (63) -

cours de theatre paris
cours de theatre paris United States
2017/9/30 下午 11:02:01 #

Thank you for your article.Really looking forward to read more. Cool.

回覆

can ho dic phoenix
can ho dic phoenix United States
2017/10/6 下午 10:37:31 #

Thank you ever so for you blog post.Really looking forward to read more. Really Great.

回覆

buy hacklinks
buy hacklinks United States
2017/10/9 下午 12:32:58 #

Wow, great article post.Really thank you! Keep writing.

回覆

Osimi seaview
Osimi seaview United States
2017/10/9 下午 04:28:20 #

I really enjoy the blog article.Thanks Again. Want more.

回覆

solarmovie
solarmovie United States
2017/10/10 下午 06:14:59 #

A round of applause for your article post.Thanks Again.

回覆

Sterling Businesses Ltd
Sterling Businesses Ltd United States
2017/10/10 下午 08:23:45 #

I really enjoy the post. Really Cool.

回覆

pirater un compte facebook
pirater un compte facebook United States
2017/10/10 下午 10:41:32 #

Thank you for your blog article.Really looking forward to read more. Want more.

回覆

buy hacklink
buy hacklink United States
2017/10/12 下午 07:06:27 #

Im obliged for the blog post. Cool.

回覆

site web
site web United States
2017/10/14 下午 01:46:15 #

Really enjoyed this post.Really thank you! Keep writing.

回覆

dragon city hack unlimited gems apk
dragon city hack unlimited gems apk United States
2017/10/15 下午 01:47:02 #

Im obliged for the post.Really looking forward to read more. Great.

回覆

omega xl
omega xl United States
2017/10/15 下午 06:30:28 #

Fantastic blog article.Really thank you! Fantastic.

回覆

sletrokor review
sletrokor review United States
2017/10/17 下午 06:38:04 #

Fantastic blog post.Really thank you! Cool.

回覆

The Avila 2
The Avila 2 United States
2017/10/19 上午 04:00:41 #

Appreciate you sharing, great article.Much thanks again. Will read on...

回覆

VigRx Plus
VigRx Plus United States
2017/10/19 上午 05:41:25 #

Very neat post.Thanks Again. Much obliged.

回覆

learn the facts here now
learn the facts here now United States
2017/10/19 下午 04:24:07 #

Thanks again for the article post.Really thank you! Cool.

回覆

pure slim 1000 review
pure slim 1000 review United States
2017/10/20 上午 01:54:07 #

Thanks for the blog article.Much thanks again. Fantastic.

回覆

DIC Phoenix
DIC Phoenix United States
2017/10/21 上午 01:29:49 #

This is one awesome blog post.Really thank you! Cool.

回覆

carte grise en ligne
carte grise en ligne United States
2017/10/21 上午 05:11:45 #

Really appreciate you sharing this blog post.Much thanks again. Keep writing.

回覆

elakekassa suomi
elakekassa suomi United States
2017/10/21 下午 03:36:20 #

This is one awesome post. Will read on...

回覆

Turbotax phone number
Turbotax phone number United States
2017/10/24 上午 05:56:02 #

I really liked your blog article.Much thanks again. Keep writing.

回覆

can ho osimi
can ho osimi United States
2017/10/28 上午 07:23:15 #

Really enjoyed this blog. Cool.

回覆

EZ Battery Reconditioning
EZ Battery Reconditioning United States
2017/10/30 上午 06:19:39 #

Really informative blog.Really looking forward to read more. Cool.

回覆

mamaweeb
mamaweeb United States
2017/11/1 上午 06:31:14 #

I value the article post.Really thank you! Really Great.

回覆

phenocal
phenocal United States
2017/11/1 下午 01:51:51 #

Fantastic article.Really thank you! Much obliged.

回覆

phentaslim
phentaslim United States
2017/11/3 上午 11:35:36 #

Thanks-a-mundo for the post.Thanks Again. Cool.

回覆

avocat criminel montreal
avocat criminel montreal United States
2017/11/16 下午 06:31:17 #

Thank you for your article.Thanks Again. Really Cool.

回覆

fashion
fashion United States
2017/11/23 下午 09:59:43 #

I am so grateful for your blog.Thanks Again. Fantastic.

回覆

It Company In Auckland
It Company In Auckland United States
2017/11/25 下午 06:57:20 #

Im thankful for the blog post.Thanks Again. Really Cool.

回覆

Chad Boonswang and Jeffrey Goodman
Chad Boonswang and Jeffrey Goodman United States
2017/11/26 下午 06:06:55 #

I really liked your blog post.Really thank you! Cool.

回覆

Chad Boonswang SEO
Chad Boonswang SEO United States
2017/11/27 上午 12:12:06 #

A big thank you for your blog post.Really thank you! Want more.

回覆

fake car wreckers
fake car wreckers United States
2017/11/29 下午 04:34:24 #

I am so grateful for your blog.Really looking forward to read more. Really Great.

回覆

Calla Garden
Calla Garden United States
2017/11/29 下午 11:10:37 #

Thanks for the blog.Thanks Again. Really Great.

回覆

business trade lines
business trade lines United States
2017/12/1 上午 12:59:33 #

Very good post.Really looking forward to read more. Really Great.

回覆

porno
porno United States
2017/12/1 下午 04:40:34 #

Major thankies for the blog article.Much thanks again. Awesome.

回覆

Build Business Credit
Build Business Credit United States
2017/12/3 上午 04:58:26 #

Really enjoyed this blog article. Really Great.

回覆

sextus.mobi
sextus.mobi United States
2017/12/5 上午 09:45:46 #

Very neat article post.Really looking forward to read more. Keep writing.

回覆

Very informative blog post.Much thanks again. Want more.

回覆

Say, you got a nice blog post.Really thank you! Keep writing.

回覆

site legalize
site legalize United States
2017/12/10 下午 07:22:29 #

Great, thanks for sharing this post.Really thank you! Fantastic.

回覆

you can look here
you can look here United States
2017/12/14 下午 04:21:26 #

Great, thanks for sharing this blog post.Thanks Again. Want more.

回覆

Christmas Music
Christmas Music United States
2017/12/14 下午 10:53:09 #

Fantastic article.Really thank you! Great.

回覆

tips lose weight
tips lose weight United States
2017/12/17 上午 12:21:06 #

Thanks again for the article post.Thanks Again. Keep writing.

回覆

I cannot thank you enough for the article.Thanks Again.

回覆

Coffee
Coffee United States
2017/12/17 下午 05:43:48 #

Thank you for your post.Thanks Again. Great.

回覆

Degreeshortcut
Degreeshortcut United States
2017/12/18 上午 12:47:18 #

Thank you for your blog.Thanks Again. Cool.

回覆

earn extra cash
earn extra cash United States
2017/12/20 下午 06:56:50 #

Thanks again for the blog article.Much thanks again.

回覆

canon drivers
canon drivers United States
2017/12/23 上午 06:02:39 #

I truly appreciate this blog.Thanks Again.

回覆

Looking forward to reading more. Great blog.

回覆

hp driver
hp driver United States
2017/12/25 下午 06:04:11 #

I think this is a real great blog.Much thanks again. Great.

回覆

Thanks for sharing, this is a fantastic post.Much thanks again. Awesome.

回覆

Very informative article post. Really Cool.

回覆

SOCCER HIGHLIGHTS
SOCCER HIGHLIGHTS United States
2017/12/26 下午 02:49:26 #

Really informative blog post. Cool.

回覆

canon printer series
canon printer series United States
2017/12/27 下午 07:16:13 #

Really enjoyed this article post. Great.

回覆

hp drivers
hp drivers United States
2018/1/2 上午 09:54:38 #

Thank you ever so for you article.Really thank you! Want more.

回覆

her explanation
her explanation United States
2018/1/2 下午 05:59:44 #

Very good post.Really thank you! Awesome.

回覆

Im thankful for the post. Cool.

回覆

hp drivers
hp drivers United States
2018/1/3 上午 09:17:48 #

Very good blog.Really looking forward to read more. Fantastic.

回覆

best Bitcoin casinos
best Bitcoin casinos United States
2018/1/4 下午 07:58:28 #

I truly appreciate this article.Really looking forward to read more. Will read on...

回覆

hp printer driver
hp printer driver United States
2018/1/5 下午 05:56:42 #

I really liked your post.Really looking forward to read more. Want more.

回覆

FBA
FBA United States
2018/1/6 上午 10:02:56 #

Fantastic blog.Thanks Again. Fantastic.

回覆

web hosting
web hosting United States
2018/1/10 上午 11:30:42 #

I appreciate you sharing this blog. Fantastic.

回覆

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List