WPF - Attached Property 深入探討

17 December 2011 — Written by Sky Chang
#Silveright#WPF

此篇延續上一篇Dependency Property內容,上一篇談到最後,提到了一個初次進入WPF或是Silverlight時,會覺得很奇怪的地方,例如說設定DockPanel的上下左右對齊,通常我會覺得說,至少會這樣寫 ( 小弟膚淺的認知. )。

<DockPanel xxx=left>
    <Button/>
</DockPanel>

但在WPF裡面,卻是這樣寫。

<Button DockPanel.Dock="Top">

程式碼的話,會這樣寫。

DockPanel.setDock(btn,Dock.Top);

沒錯,並沒有看錯,呼叫一個靜態類別DockPanel,然後使用靜態方法setDock(),裡面第一個參數是要設定位置的控制項,第二個參數則是利用Dock的列舉型別來設定上下左右。

老實說,我第一次看到,會覺得很詭異,為什麼會用這麼詭異的方式進行設定呢?也完全顛覆了我之前的認知( 所以說,我很膚淺嘛~~ )。

Attached Property

中文翻譯叫做附加屬性;既然Attached Property會放在Dependency Property後面講,大家應該就可以猜的到了,會用那麼奇怪的寫法,其實這個的原始技術還是在Dependency Property。

首先我們先來看,實際的DockPanel原始碼,其實內容和之前講的Dependency Property類似,比較不同的是,這裡的DockProperty是使用DependencyProperty.RegisterAttached來進行註冊的,此外,get和set裡面,都有傳入UIElement進來,簡單的說,就是使用傳進來的UIElement來呼叫SetValue和GetValue,而非是呼叫DockPanel的SetValue和GetValue。

public class DockPanel : Panel
{
    public static readonly DependencyProperty DockProperty;
    public static void SetDock(UIElement el,Dock dck)
    {
        el.SetValue(DockProperty,dck);
    }
    public static Dock GetDock(UIElement el)
    {
        return (Dock) el.GetValue(DockProperty);
    }
}

那這樣代表甚麼,記不記得前面Dependency Property有提到,利用SetValue會將資料存到某個Collection裡面,所以簡單的說,我們在DockPanel設定了靜態方法SetDock和GetDock,但實際上,上下左右的設定,會存放到,由SetValue第一個參數傳入進去的UIElement元件裡面去。而這種感覺,就像是我們在DockPanel設定了DockProperty這個屬性,但實際上,此屬性附加到了真實會用到的控制項上面,所以才會有Attached Property之稱。

Attached Property的一些特點

前面有提到,既然不是呼叫DockPanel裡面的SetValue和GetValue,所以我們可以發現到,其實時要實踐attached property的類別是不需要延生自DependencyObject的!,當然要實際SetValue和GetValue的類別還是要延生自DependencyObject。

其次,其實前面寫到這樣的設定上下左右。

DockPanel.SetDock(btn,Dock.Top)

懂得原理後,其實我們也可以這樣寫,道理是相通的。

btn.SetValue(DockPanel.DocProperty,Dock.Top)

所以這兩種基本上是一樣的,也因此,Attached Property算是Dependency Property的一種延伸型態,

為什麼使用Attached Property

要提到這個,又要講古了,以前的Win Forms程式可能會這樣寫。

btn.Dock = Dock.Top

而使用這種方法,最大的問題就是,如果btn沒有在Dock下面,那這個屬性就等同於沒有用,所以後來WPF才實作出這種有彈性的天才作法 ( 老實說,真的很厲害… ),所以以後要寫WPF,要設定上下左右,就不會覺得奇怪啦..

參考資料

Sky & Study4.TW