[WPF]ListView點擊列頭排序功能實現
這是一個非常常見的功能,要求也很簡單,在Column Header上顯示一個小三角表示表示現在是在哪個Header上的正序還是倒序就可以了。微軟的MSDN也已經提供了實現方式。微軟的方法中,是通過ColumnHeader Template實現的,一共要維護至少兩個Header Template,一個顯示正三角,一個顯示倒三角。在用戶點擊Header的時候同時切換使用的Template。如果你的ListView只提供Sort功能,這個方法就可以了。但是如果你的ListView還在在Header中提供Filter功能呢?如果還需要用戶可以配置是否開啟Sort和Filter功能呢?那么你就需要6個Template來處理Sort和Filter的組合。如果在Header本來就有好幾種(文字Header、畫片Header等)或是要放入更多的功能呢?顯然微軟的這個方式只能用于技術演示(當然MSDN本來就是這個目的),面對實際項目時就會力不從心。Google搜索WPF ListView Sort,可以找到很多不同的實現方式。
1.?????? SwitchOnTheCode:使用Adorner Layer,重寫Adorner的OnRender方法,畫出一個三角形。畫個三角可以,要畫個有發光、漸變、動畫效果的三角,代碼會變得很難維護。而且不能用Blend去編輯這個樣式。不過思路是很好的,因為它不會占用控件的現有的任何屬性,就不會有微軟的方式中功能組合的問題。
2.?????? Jeol Rumerman’s Blog:繼承GridViewColumn,擴展出Sort功能。還是用Header Template,更糟糕的是,為加一個功能而使用繼承本身就不是一個很好的設計。同理要加個Filter功能,是不是還要繼承出一個FilteredGridViewColumn和FilteredAndSortedGridViewColumn呢?不僅要處理Template的組合,還會產生類膨脹,實在是不可取。
3.?????? CodeProject WPFListViewSorter:與微軟的方式一樣,只是通過自定義Sorter函數解決了微軟的方式中,把Column Header上的名字,當作Sort Property的問題。
4.?????? Thejoyofcode:通過Attached Property解決了同樣的問題,而且沒有界面顯示的實現。而且還繼承出了一個SortableListView。缺點就不再解釋了。
5.?????? Marlongrech:提供了Disable/Enable Sort功能。不過也是用HeaderTemplate做界面實現。(突然發現Wordpress可以訪問了)
沒有找到一個滿足我要求的實現方式,每個解決方案都只是關注于自己要解決的問題的那一個點上。當然在Blog里讓示例簡單一些也沒有錯。那就讓我把他們所解決的問題集成到一個示例中。要求也不多。
1.?????? 不影響現有功能。
2.?????? 不獨占現有屬性。
3.?????? 使用組合,而不是繼承。
第一個方案,使用Adorner Layer是個很好的思路,Adorner Layer相當于一個畫板,我畫在這里,別的功能畫在那里就是了,所以不會影響現有功能也不算獨占現有屬性。它的示例中占用了Tag來描述使用哪個屬性排序。我們用Attached Property替換掉就可以了。然后就剩下一個問題了——不要畫三角。我們想用Template。這樣不同的地方的樣子可以有不一樣的界面效果而又不用修改代碼。但是問題是Adorner是沒有Template的。
參考了兩篇關于Adorner Layer的文章。
1.?????? Adorners in WPF
2.?????? Visual Level Programming vs Logical Level Programming
寫了一個晚上的代碼,終于搞出一個自我感覺良好的實現出來。在ListView上添加Sort功能,只需要添加一個Attached Property就可以。代碼如下。
?

