一般情況下,我們都傾向於使用一個組織比較好的獨立界面來錄入或者展示相關的數據,這樣處理比較規範,也方便顯示比較複雜的數據。不過在一些情況下,我們也可能需要直接在GridView表格上直接錄入或者修改數據,這種對於欄位比較少,而且內容相對比較簡單的情況下,效率是比較高的一種輸入方式。本篇隨筆主要介紹在... ...
一般情況下,我們都傾向於使用一個組織比較好的獨立界面來錄入或者展示相關的數據,這樣處理比較規範,也方便顯示比較複雜的數據。不過在一些情況下,我們也可能需要直接在GridView表格上直接錄入或者修改數據,這種對於欄位比較少,而且內容相對比較簡單的情況下,效率是比較高的一種輸入方式。本篇隨筆主要介紹在DevExpress程式中使用GridView直接錄入數據並保存的實現,以及使用Winform分頁控制項來進行數據直接錄入的實現操作。
1、在GridView上展示數據
在GridView上展示數據,只需要綁定數據源給對應的GridControl控制項即可,比較簡單,可以綁定的數據格式也是很多,可以是DataTable,也可以支持IEnumerable格式的IList<T>集合對象等等,在我的框架中,傾向於使用IList<T>這種實體類集合的方式。
在網上大多數例子,綁定的數據源多數採用的是基於DataTable的方式,這種方式顯示的數據受制於不同資料庫的特點,欄位可能大小寫不一樣,而且DevExpress操作行列的欄位是大小寫敏感的,因此如果你要欄位名獲取值的時候,傳入的欄位名一定是要大小寫一致,因此在資料庫不同的時候,如Oracle查詢到的欄位全部是大寫的,SQLServer則是混合模式的(可以是Pascal,也可以是大寫、小寫)。
採用實體類集合對於框架層次的操作有很多好處,可以強類型,而且不受具體資料庫的影響,所有交互均通過實體類或者其集合進行處理,相對來說有很大的優勢。
一般情況下,對實體類的數據源,我們可以通過下麵的方式進行數據綁定(使用分頁控制項的數據綁定方式)。
List<DictDataInfo> list = BLLFactory<DictData>.Instance.FindWithPager(condition, this.winGridViewPager1.PagerInfo); this.winGridViewPager1.DataSource = list;
如果需要在GridView上對記錄進行新增修改的,也就是需要存儲綁定數據的狀態的,那麼就不能直接使用List<T>集合,而需要使用其BindingList<T>的集合,同樣BindingList<T>實現了IList<T>介面,我們可以通過構造函數new BindingList<T>(list)方式進行類型轉換,然後重新綁定到數據源即可。
修改下上面的處理,我們可以得到如下的數據綁定方式:
/// <summary> /// 綁定GridControl控制項的數據源 /// </summary> private void BindData() { //使用BindingList可以進行編輯記錄,否則無法存儲新增記錄內容 var list = BLLFactory<DictData>.Instance.Find(treeConditionSql); this.gridControl1.DataSource = new BindingList<DictDataInfo>(list); }
預設情況下,如果這樣綁定,那麼欄位列名稱會是實體類的屬性名稱,英文的,顯然這樣不太符合我們的顯示處理,我們需要限定幾個欄位,而且需要顯示中文內容,那麼我們應該為GridView構建幾個綁定的列欄位才可以。
例如我們可以通過函數進行欄位列的構建工作,如下所示。
其中的CreateColumn是為了簡化處理模式引入的擴展函數,主要就是實現綁定欄位的增加的,可以理解為下麵代碼的處理
這樣我們綁定數據源後,就可以顯示指定的一些欄位內容了,而且是中文列名稱,如下效果所示。
2、在GridView上錄入數據和保存數據
但是,上面小節只是說明瞭數據如何綁定顯示的,如果需要在GridView上直接錄入數據,那麼還需要做一些特殊的代碼處理的。
在上面我們介紹使用BindingList<T>的數據源方式,確保可以顯示並錄入實體類集合數據的,如下代碼綁定數據源所示。
如果我們需要設置GridView能夠直接錄入數據,那麼需要設置下麵幾個屬性,特別是紅色那行。
grv.OptionsBehavior.ReadOnly = false; grv.OptionsBehavior.Editable = true; grv.OptionsView.NewItemRowPosition = NewItemRowPosition.Bottom;
對於一些常規的GridView初始化,我們可以通過一個擴展函數實現它的屬性設置。
grv.InitGridView(GridType.NewItem, false, EditorShowMode.MouseDownFocused);
我們錄入新的數據行時候,往往需要設置一些相關的屬性,如父ID什麼的,那麼需要在InitNewRow事件裡面進行處理,如下所示,我們希望在新建記錄的時候,保留記錄這個記錄的父ID(來源自左側樹節點的ID信息)
其中代碼
grv.SetRowCellValue(i, "DictType_ID", typeId);//存儲記錄的父ID
需要我們在這個GridView裡面有一個隱藏的欄位存在(如本例的DictType_ID欄位),否則無法存儲這個記錄內容的。
如果我們需要在錄入完成某個欄位內容後,其他欄位也做相應的改變,如觸發關聯變化,那麼可以在CellValueChanged事件進行處理,如本例我們希望名稱增加後,值和名稱一致變化,那麼代碼如下所示。
這樣我們在界面編輯的時候,就可以得到下麵的效果了。
完成上面步驟,如果我們需要在錄入數據後校驗錄入的信息,並提交資料庫處理,如果成功則提示,那麼就需要在事件ValidateRow裡面進行處理了。
校驗記錄內容,我們可以通過下麵的代碼進行處理。
不過一般情況下,我們可以使用擴展函數來封裝這些校驗的處理,已達到簡化代碼的目的。
校驗通過後提交資料庫,我們首先需要做的方式是定位記錄集合裡面當前的記錄,把它轉換為具體的實體類對象,然後寫入新記錄或者更新處理,如下所示。
運行程式,併在GridView中錄入記錄後,並逐一回車,跳轉到新一行的時候,觸發數據校驗和保存操作,保存成功後提示用戶,並可以繼續錄入新的記錄,非常方便,這個就是使用GridView直接錄入數據並保存的方便地方。
結合GridControl的右鍵菜單,我們可以實現數據的刪除、列印、導出等常規的功能整合。
3、基於Winform分頁控制項的數據展示和錄入
在數據記錄比較少的情況下,直接使用GridView進行展示全部記錄,沒有什麼問題。但是在數據記錄比較多的時候,如果用GridView全部展開所有的記錄,會比較影響性能,比較好的方式就是對數據進行適當的分頁。
在Winform開發中,我們使用封裝好的分頁控制項來展示數據,這個分頁的特性已經整合在Winform開發框架、混合式開發框架等框架底層裡面了,直接調用相應的框架業務類方法,即可獲取對應業務表的分頁記錄,非常方便。
前面兩個小節都是基於原生的GridView控制項對象進行數據的展示和錄入,分頁控制項本身也是封裝GridView控制項的,因此也是可以直接利用它來進行數據的錄入處理的。使用分頁控制項,可以高效提高數據的查詢速度,另外可以利用代碼生成工具Database2Sharp工具進行快速開發好Winform界面,然後進行一定的修改即可,非常方便。
我們來看看使用分頁控制項做的數據展示和錄入界面效果圖。
利用分頁控制項的方式和前面的直接使用GridView的方式大同小異,只是一些細節處理上進行修改即可。
分頁控制項,在利用代碼生成工具Database2Sharp的Winform界面生成的時候,自動帶有下麵的分頁控制項初始化代碼,我們屏蔽其中的新增和編輯處理事件,因為我們使用直接錄入的方式,不需要彈出對話框進行處理。
代碼如下所示。
由於我們使用分頁控制項,其在數據綁定的時候,列是自動創建的,因此我們不需要為GridView指定數據列,我們使用分頁控制項後的InitGridView的代碼如下所示。
/// <summary> /// 初始化GridView /// </summary> private void InitGridView() { var grd = this.winGridViewPager1.gridControl1; var grv = this.winGridViewPager1.gridView1; #region GridView控制項初始化 grv.InitGridView(GridType.NewItem, false, EditorShowMode.MouseDownFocused, ""); grv.InitNewRow += delegate(object sender, InitNewRowEventArgs e) { //數據記錄初始化的時候,設置ID和父節點的ID if (this.tree.FocusedNode != null) { var i = e.RowHandle; var typeId = this.tree.FocusedNode.GetValue("ID"); grv.SetRowCellValue(i, "ID", Guid.NewGuid().ToString()); grv.SetRowCellValue(i, "DictType_ID", typeId);//存儲記錄的父ID } }; grv.CellValueChanged += delegate(object sender, DevExpress.XtraGrid.Views.Base.CellValueChangedEventArgs e) { //如果欄位的值發生改變,觸發其他值改變則在此處理 if (e.Column.FieldName == "Name") { string value = string.Concat(grv.GetRowCellValue(e.RowHandle, "Value")); if (string.IsNullOrEmpty(value)) { grv.SetRowCellValue(e.RowHandle, "Value", e.Value); } } }; grv.ValidateRow += delegate(object sender, ValidateRowEventArgs e) { var result = grd.ValidateRowNull(e, new string[] { "Name" }); //校驗通過後提交資料庫 if (result) { //獲取當前操作的記錄對象 var info = grv.GetFocusedRow() as DictDataInfo; //如果記錄對象非空,則可以寫入或者更新 if (info != null) { result = BLLFactory<DictData>.Instance.InsertUpdate(info, info.ID); //如果不能寫入,提示用戶 if (!result) { e.Valid = false; e.ErrorText = string.Format("寫入數據出錯"); } else { base.ShowMessageAutoHide(); } } } }; #endregion }
綁定數據源的方法BindData和直接生成的代碼沒有太大的差別,只是把GridView設置為可編輯即可,代碼如下所示。
這樣我們就可以實現基於Winform分頁控制項的基礎上進行數據的直接錄入操作了,處理方式就是先利用代碼生成工具Database2Sharp進行Winform界面生成,然後進行微調代碼即可,非常方便就可以實現這種快捷的數據錄入了。
4、基於主從表數據錄入的處理
在前面的記錄保存和顯示裡面,都是採用一個視圖的方式進行數據的展示和錄入的,如果對於主從表的記錄同時錄入,那麼就需要主從表兩個GridView來進行展示和數據錄入的了,對於主從表錄入相對複雜一些,具體如何操作呢?
這裡我們依舊採用分頁控制項來進行數據的分頁及直接錄入數據操作,而且增加了主從表數據同時在一個GridControl界面上進行處理。
這樣主表記錄為字典類型,從表為字典明細項目,得到的數據展示界面效果如下所示。
當然我們可直接在底部進行數據的錄入,包括主表記錄和從表的明細記錄,都可以一氣呵成的錄入併進行保存處理的,界面效果如下所示。
GridView的主從關係需要設置好集合的映射關係,我們需要通過設置GridLevelNode集合實現主從表關係的處理的。
初始化從表的GridView2和主從表關係的代碼如下所示
通過上面的初始化代碼,指定了主從表的關係後,我們還需要對綁定的數據源進行一定的處理,才能夠在GridControl控制項上顯示主從表關係的記錄。
首先需要定義一個業務對象,用來存儲主從關係的記錄對象。
然後在BindData綁定數據的時候,代碼處理如下即可。
這樣就可以得到開始介紹的主從表界面效果了。
數據保存的代碼和前面的操作類似,我們需要分別對GridView1和GridView2的數據保存操作進行處理,如下代碼所示。
GridView2的字典項目明細保存操作如下所示。
主從表的記錄刪除這裡需要順帶介紹一下,由於主從表公用一個右鍵菜單的刪除操作。
那麼處理的時候,我們需要判斷是操作從表還是主表記錄,對它們要分開處理,然後提示是否操作成功,如果成功,我們可以移除這行即可,避免重新更新數據導致的焦點丟失。
以上就是介紹各種在GridView界面上直接錄入數據並保存的處理操作,雖然一般情況下麵,我們建議通過獨立的彈出界面進行內容的展示和錄入,但是對於一些欄位較少,或者喜歡直接錄入記錄的用戶來說,這種方式也是一種非常不錯的體驗效果,也可以達到快速錄入的目的,可以把這種方式作為我開發框架數據非常規錄入的補充。