在Winform的分頁控制元件裡面,我們提供了很多豐富的功能,如常規分頁,中文跳脫、匯出Excel、匯出PDF等,基於DevExpress的樣式的分頁控制元件,我們在其上面做了不少封裝,以便更好的使用,其中就包括整合儲存使用者列表顯示欄位及寬度調整設定。本篇隨筆介紹這個實現的過程,通過在當前程式中序列化方式儲存一個記錄使用者設定的檔案,提供媒介的儲存和載入處理。
在一些使用者列表使用的反饋中,希望能夠在調整列表欄位和它的順序,以及能夠儲存上次調整記錄的寬度,因此,涉及到欄位可見列表、欄位順序,列寬度的內容儲存,這些功能應該是對使用者透明的,不需要開發人員干預,也不需要使用者過多操作就能實現的,也就是在使用者調整的時候,自動記錄這些資訊,並儲存起來,下一次開啟頁面的時候,自動載入上次的設定資訊即可,邏輯也算比較簡單。
因此我們需要檢測使用者對列寬度調整的事件,記錄列欄位寬度的資訊,如果使用者調整欄位顯示和順序,那麼控制元件也需要對它進行記錄起來,供下次載入使用。
對於DevExpress的列寬調整,有一個事件,我們在控制元件邏輯中實現它,記錄它的變化並儲存即可
this.gridView1.ColumnWidthChanged += GridView1_ColumnWidthChanged;
然後我們在事件的實現中,判斷使用者是否啟用自定義設定處理,然後進行儲存列寬處理即可。
private void GridView1_ColumnWidthChanged(object sender, DevExpress.XtraGrid.Views.Base.ColumnEventArgs e) { //如果不設定,預設不處理 if (!this.EnableColumnsSetting) return; GridViewHelper.SaveColumnSetting(this.gridView1, this.ParentForm?.Name); }
為了方便,我們把一些邏輯分離到一個獨立的輔助檔案上,實現程式碼如下所示。
/// <summary> /// 儲存列設定 /// </summary> /// <param name="settings">當前設定資訊</param> /// <param name="gridViewName">檢視名稱</param> /// <param name="parentFormName">父類別表單名稱,用於區分</param> public static void SaveColumnSetting(GridColumnSetting settings, string gridViewName, string parentFormName) { if (settings != null) { var folderPath = $"{Environment.CurrentDirectory}/ColumnSetting"; var filePath = $"{folderPath}/{parentFormName}.{gridViewName}.setting"; // 檢查資料夾是否存在 if (!Directory.Exists(folderPath)) { Directory.CreateDirectory(folderPath); } using (var stream = new FileStream(filePath, FileMode.Create)) { var formatter = new BinaryFormatter(); formatter.Serialize(stream, settings); } } }
上面主要就是對設定資訊進行序列化到一個檔案中進行中轉,從而避免資料庫的處理,同時又會因為不同使用者記錄不同的設定資訊。對於不同的頁面,我們通過表單名稱來區分不同的設定,因為分頁控制元件場景需要一個唯一的標識來區分不同的資料場景。
而對於可見欄位,以及它的順序調整,那麼我們為了方便,提供一個設定的介面給終端使用者使用即可,通過列表右鍵選單觸發入口,如下介面所示。
在列表框中列出介面的所有列(包括隱藏列),並通過拖動或者按鈕調整順序,通過勾選設定可見性,如下介面所示。
上面的列表控制元件,是一個標準的CheckedListBox控制元件,通過處理它的拖動事件,實現可拖動順序的調整。
// 繫結 ListBoxControl 控制元件的事件,實現拖拉處理 listBoxControl.DragDrop += ListBoxControl_DragDrop; listBoxControl.DragOver += ListBoxControl_DragOver; listBoxControl.MouseDown += ListBoxControl_MouseDown;
而讀取上面的列表中的可見列欄位及順序,我們通過組態檔中進行讀取,並反序列化即可。
/// <summary> /// 獲取設定資訊 /// </summary> /// <param name="gridView">當前檢視</param> /// <param name="parentFormName">父類別表單名稱,用於區分</param> /// <returns></returns> public static GridColumnSetting GetSettings(GridView gridView, string parentFormName) { var folderPath = $"{Environment.CurrentDirectory}/ColumnSetting"; var filePath = $"{folderPath}/{parentFormName}.{gridView.Name}.setting"; if (!File.Exists(filePath)) return null; //反序列化 GridColumnSetting settings = null; using (FileStream stream = new FileStream(filePath, FileMode.Open)) { var formatter = new BinaryFormatter(); settings = (GridColumnSetting)formatter.Deserialize(stream); } return settings; }
對於使用者調整後的設定儲存,記錄好相關資訊後進行序列化到檔案中即可,如下實現邏輯所示。
private void btnOK_Click(object sender, EventArgs e) { //記錄所有的列寬 var sb = new StringBuilder(); var visibleSb = new StringBuilder(); int index = 0; foreach (var objItem in this.listBoxControl.Items) { var item = objItem as CListItem; if (item != null) { var checkState = this.listBoxControl.GetItemChecked(index); if (checkState) { var column = this.GridView.Columns.ColumnByFieldName(item.Value); if (column != null) { sb.Append($"{item.Value}:{column.Width},"); visibleSb.Append($"{item.Value},"); } } } index++; } var columnsWidth = sb.ToString().Trim(','); var columnsVisbile = visibleSb.ToString().Trim(','); var settings = new GridColumnSetting(columnsWidth, columnsVisbile); //如果不設定,預設不處理 GridViewHelper.SaveColumnSetting(settings, this.GridView.Name, this.Owner?.Name); }
最終,我們在開發具體頁面資料展示的時候,把分頁控制元件拖動到介面上就可以了,預設具有這些效果,不需要另外增加實現程式碼,從而通過封裝的方式,簡化了很多基礎的功能處理,並能夠給使用者一致的體驗和介面效果。