WPF DataGriw采用編輯模式,用戶可以雙擊最尾的空白行從而新加一條記錄.也可以選擇行記錄后按鍵盤Del鍵來刪除選擇的記錄,做完一系列的操作后一次性把數據都保存到遠程數據庫中.那在MVVM中Ui和后台是分離的.不能直接知道那樣那數據是新加\還是修改\有那些數據是被刪除的了.那當前操作的集合表面保存的數據就不一定是這次一系列所有操作的數據.那只是操作過后所要保留下來的數據而以.為了觸屏這樣子的問題很多人一般都會寫多幾個按鈕(如下圖).把相應的操作都進行記錄下來.這本來也不是什么不好的解決方法.但要是DataGrid這控件本來就是使用方便.管理數據還要這么多要求.那就有點偏離了這個控件的使用要求了.
這樣的事情只有一兩個業務單據就沒什么.如果出現很多那就死得人多了.加上如果MVVM是操作的話大大加深了UI與后台的藕合度這可不利於維護的.出於項目功能還是自己寫一個對應的集合吧.那自己寫集合當然是要了我解集合所用到的接口DataGrid對操作要用到那些接口.寫集合一般用到的接口或者說我們平時用到的List<T>這個數據集合是對實現了主要兩個接口的分支IList<T>, IList這兩個接口前者要做的是對泛型的管理(只管增刪),后者是對Ojbect的管理(管增刪之余還有屬性說明這個合集是否固定長度[IsFixedSize],是否只讀[IsReadOnly]). 那自定義的集合類最基本要實現的接口IList<T>, IList這兩個接口下的所有方法.[ IsFixedSize]屬性讓DataGrid集合容器知道當前數據集合是否可以添加\刪除.那我們就繼承這兩個接口定義我們新的接口. 使用我們在新增時可付默認值,刪除時可以驗證數據是否刪除.這兩功能采用委托方法.為什么是委托而不是事件.個人覺得只有一個地方執行就夠.沒必要在這付點默認值在那個地方付點默認值.刪除也是一樣在一個地方控制就行了.
public class ActionList<T> : IActionList<T>,IActionList, INotifyCollectionChanged
{
public ActionList();
public ActionList(IEnumerable<T> collection);
}
構造函數說明.一個為空的構造函(這個原空集合最后所才生的都是要添增的數據),有參數的構造函數(集合最后保留的數據參數的默認為修改的集合中,如果有刪除操作記錄則移到移除集合中.如有添就新的則為新增的記錄)
只於為什么要加上INotifyCollectionChanged主要是為了MVVM模式下UI可以及時更新顯示數據,事件的構造函數如果為了能在Silverlight上也通用的話,基本上是要采用多參數,有些動作在Silverlight也不存在只要4個動作類型[Add,Remove,Reset,Replace].為能了一個文件通用往往會加入#if !SILVERLIGHT來判斷編譯環境.Silverlight中只有3種事件的構造函數,比起WPF上的12種就真的簡單很多了.在本編中用到3個參數的(動作[只能Add,Remove],數據,索引)的函數來處理增刪,[Reset]動作只能用單個參數的.[Replace]動作則要用到4個參數的.
本來是泛型的集合類所以都是圍繞着List<T>這個字段來操作.IActionList<T>接口為主要實現,IActionList則為顯式實現.普通的接口實現與顯式實現的區別在於顯式實際的接口在調用實現類時,現實類是不會見到對應的屬性和方法只有轉換成接口時才能調用,從實現類可以選擇性的暴露相關屬性和方法更好的突出實現類自己的特性.不足之點就是都要實現功能不像繼承那可以什么都不用寫.
在什么時候往我們定義的集合中添加數據呢.由於框架所有的數據集合處理都是基本IList接口的(還真的不知道為什么沒有IList<T>接口,但有實現IList<T>接口的類就一定會實現IList,所以最終處理的都是IList接口我覺得可能IList是對數據沒有約束性更符合所有類型都派生於Object對象吧),所以我們主要是在IList接口中的Add,Remove處理前還要執行我們的委托判斷.處理時把數據判斷好分類放入對應的數據集合中就行了.處理后當然要加上對就的INotifyCollectionChanged事件前台UI才會跟着變.這樣子委托有值時就會執行委托生成默認值或者判斷當前記錄是否真的要刪除.操作了又會在對應的數據集合中添加上對應的數據.前台UI也會更着變化.
由於INotifyCollectionChanged不支持數組的事件采用數組會有異常(Silverlight沒有對應的方法傳參數UI只會變化第一條記錄,而WPF下有對應的參數但前台UI更新數據時提示不支持集合的變化直接出現異常錯誤死了).如果在寫數組操作時要用循環把數組中的數據一條條執行事件更新到前台UI中.
平時用到的集合最后還是依賴於IList而泛型只是為了數據的直觀\操作的方便進行二次封裝而以.什么Array\ArrayList\List<T>\CollectionBase\Object[]都是實現IList接口,不過數組是個比較特別的集合通過Array抽象類和編譯器動態生成的.能通過數據查到所用的方法和屬性都來源自Array抽象類,但在Array抽象類中則找到相關的派生類.