WPF自定義集合控件概述與遇到的問題
WPF中涉及到控件,那么就不可能繞過Template。首先咱們來看一下WPF中基礎集合控件ItemsControl涉及到的幾個Template。
- ItemsControl自身的Template,類型為ControlTemplate,其內(nèi)部聲明了一個ItemsPresenter用以呈現(xiàn)下述第2個Template。當我們?yōu)榧峡丶x予自定義模板時,ItemsPresenter不可丟棄,否則就失去了集合控件的意義;
- ItemsPanel,類型為ItemsPanelTemplate,其內(nèi)容一般為可擁有多個子項的布局控件,如StackPanel、Grid等;
- ItemTemplate,類型為DataTemplate,呈現(xiàn)各數(shù)據(jù)項。
此時有人會問,數(shù)據(jù)項對應的類型是ControlTemplate的Template跑哪里去了?說的是呀,話說只要是繼承自Control的控件都應該有這個Template屬性,你看ItemsControl不就有嗎。那么與各子項對應的這個屬性應該怎么獲取和設置呢。ItemsControl并沒有提供給我們直接訪問子項Template屬性的方法,而是給了另一個屬性ItemContainerStyle。ItemContainerStyle對應子項控件的Style,因此我們可以通過該Style設置子項控件的Template(上述第3條實際上對應子項控件Template內(nèi)的ContentPresenter)。ItemContainerStyle對于ItemsControl是設置ContentPresenter的樣式,不過ContentPresenter并沒有Template屬性,但是對于ListBox來說,它設置的是ListBoxItem的Style。
關(guān)于為什么wpf不給我們直接設置子項控件Template的方法,我沒有特地研究過,不過我想微軟的開發(fā)人員是這么想的:也許有人希望在保持原先默認的Template,對其它屬性做一些掌控,比如可見性,那么何不如直接給你們設置所有樣式的機會呢?(上帝說,要有光。于是就有了光。我等P民感恩戴德。)
WPF靈活地樣式自定義給了開發(fā)人員極大的便利,同時也帶來了可能破壞控件內(nèi)在邏輯的問題。如何做到設計和邏輯分離,周大牛在WPF中自定義控件(3) CustomControl說的很詳細,不過由于該博文“年代久遠”,因此不排除有過時的內(nèi)容。
原本我打算自定義一個名為UserAddDelItemsControl的集合控件,該控件繼承自ItemsControl,為用戶提供自增刪子項的功能,但進行到一半的時候發(fā)現(xiàn)它的ItemsSource屬性給我造成了相當大的麻煩。ItemsSource != null即有數(shù)據(jù)源綁定時,我要去判斷可能的數(shù)據(jù)源類型,謝天謝地,大部分實體數(shù)據(jù)源都繼承自IList,該接口有我期望的Insert、Remove等方法。但是假設我Insert一個新數(shù)據(jù)項(注意此處是數(shù)據(jù)項)的時候,我要不要去刷新界面,以及如何去刷新界面以反映后臺數(shù)據(jù)列表的更改呢,所以我又要去判斷數(shù)據(jù)源是否繼承自INotifyCollectionChanged。假如它沒有繼承自INotifyCollectionChanged,那么我該怎么辦?或許我該使用 ICollectionView.Refresh()方法?或許最終可以實現(xiàn),但這樣的控件并不能使我滿意。我意識到要實現(xiàn)一個優(yōu)良的可增刪項的集合控件的真正重點和難點是需要重寫ItemsSource屬性,甚至要為其自定義一套數(shù)據(jù)源處理邏輯。水太深鳥!時間不多,我只能暫時放棄。
不過該項工作并沒有白做,除自定義控件的知識外,重溫并加深了關(guān)于Command、VisualState(4.0,可以理解為Trigger的升級版)的知識。
- RoutedCommand,可理解為事件event,或者更本質(zhì)上,其實是一個信號??丶ㄈ绨粹o)觸發(fā)這個命令,有人(類或?qū)嵗┦盏竭@個命令,檢查自己能否處理(擁有的CommandBindingCollection是否包含與這個命令相關(guān)的CommandBinding(檢查其Command屬性)),若找到對應的CommandBinding,那么就執(zhí)行CommandBinding的Executed邏輯。
- 按第1條理解,RoutedCommand定義在哪里并不要緊,一般將之定義為自定義控件的靜態(tài)字段。
- 事件和命令的區(qū)別,個人理解:事件的信號源是一個,關(guān)注者收到信號后做自己計劃做的事,信號源并不care關(guān)注者做什么事;命令的信號源可以有多個,當然關(guān)注者也可以有多個,一般來說,所有信號源都期望關(guān)注者執(zhí)行一個或一組邏輯,而關(guān)注者也遵循它們的意愿,這里的關(guān)注者可以理解為代理。
- 相同VisualStateGroup包含的所有VisualState互斥,使用VisualStateManager.GoToState來進行狀態(tài)跳轉(zhuǎn)。
轉(zhuǎn)載請注明本文出處:http://www.rzrgm.cn/newton/archive/2012/12/28/2836672.html。

浙公網(wǎng)安備 33010602011771號