《本文於2021/06/18首發於博客園》
1,前幾天學習一個項目的時候,遇到了PasswordBox這個控件,由於這個控件的Password屬性,不是依賴屬性,所以不能和ViewModel層進行數據綁定。
2,但是要實現前后端徹底的分離,就需要綁定,那么下面我的本文的主角“附加屬性”就要出場了。
3,附加屬性的概念,就是類(控件類)本身沒有這個屬性,我們給它一個我們定義的屬性。那是怎么給的呢?
4,怎么給的,剛開始我也很迷惑,其實就是在xmal文件中,在控件屬性中,直接寫上我們定義的附加屬性就好(放心,編輯器是不會報錯的)。
5,附加屬性,是一個屬性,屬性必須依附於類,也就是我們要來定義一個類,來容納我們的附加屬性。

要定義一個附加屬性,需要這么多的代碼,別擔心,這些代碼不需要您手動敲出來,在vs的類中,找一個合適的地方,輸入“propa”,然后根據編輯器的提示,按兩次Tab鍵,
編輯器會自動幫助您完成這些代碼。然后再次按Tab鍵,編輯器會引導您做“完形填空”(不會完型填空的朋友,您可以查下資料,本文不再贅述),直到您按下Enter鍵,這個附加屬性就創建完成了。
(此處的CallBack方法,是我自己定義的,不是自動生成的。什么?你說我為什么知道CallBack的參數是DependencyObject和DependencyPropertyChangedEventArgs,為什么知道CallBack可以放到
PropertyMetadata的構造函數中,因為我查從源數據了啊 ^-^ ^-^,查看下PropertyMetadata的定義就知道了(使用方法后面講)。
注意,注意,注意(重要的話說三遍,否則你的下一步將無法進行!!!)
上面定義的類,它的文件位置在這里:

7,附加屬性定義好了,怎么來使用它呢?也是一個問題,我到現在還是沒有完全扭轉過來這個思維,慚愧!!!下面講一下怎么來使用它:

注意到加藍綠色顏色的那句代碼,他的意思是,把WpfTest這個名稱空間引入進來,給它重新取一個名字,叫做local,我們定義的附加屬性所在的類,
就存在於WpfTest名稱空間,在xmal中,附加屬性所在的類,就存在於local中。總而言之,就是要引入定義的附加屬性所在的類到xaml中。
在窗體xmal中,定義一個Rectangle,在Rectangle的屬性中,寫上我們定義的附加屬性,大膽寫,盡管寫,先不要考慮為什么這樣。
因為我們定義的類,存在於名稱空間WpfTest中,而WpfTest在xaml映射在local,因此我們的附加屬性Height存在於local:AttachProperty.Height,
第一次使用這個附加屬性的時候,編輯器會報錯,提示“命名空間clr-namespace:WpfTest中不存在AttachProperty名稱”,

如果確定文件位置是對的,先不用管這句話,運行之后,就不會再報錯了,為什么會這樣,請路過的大神,幫忙指點一二,非常感激。
8,來到主窗體的構造函數內,寫下這句話:
然后啟動窗體,可以看到,窗體內矩形的高,由xaml中設置的50變成了我們在構造器中設置的100,那么就是說這個附加屬性對於描繪矩形起效了(注意再xaml中是雙向綁定)。
9,附加屬性的獲取:在主窗體的構造函數中,寫下這樣的代碼:

然后啟動,就可以看到MessageBox中,會顯示您在xmal中這是的rectangle的高的值,為50.
后記:1,在第五步中,我們定義了一個附加屬性,並且定義了一個CallBack委托,當值發生變化的時候,我們在委托方法中,就可以去到附加屬性的值,可以在這里編寫我們的業務邏輯。
2,全篇文章看下來,和PassowrdBox完全沒有關系對吧?因為它不是本文的重點,下面簡述一下。
3,PasswordBox的Password屬性,不是依賴屬性,那么我們就給他一個附加屬性,在CallBack中,獲取到PasswordBox的實例,指定PasswordBox的PasswordChanged事件處理程序,
在事件處理程序中,可以對model進行綁定,注意,在為PasswordBox創建附加屬性時,要指定一個string類型的默認值,用於觸發PasswordChanged事件處理程序的執行。
4,附加屬性的設置,對於控件來說,不會起任何視覺上的效果,我們還必須要在viewModel層,對拿到的附加屬性值進行處理,來使控件的視覺效果發生變化。
