在咱們通常的應用系統裏面,因爲系統是面向不一樣類型的用戶,咱們所看到的菜單會愈來愈多,多一點的甚至上百個,可是咱們實際工做接觸的菜單可能就是那麼幾個,那麼對於這種龐大的菜單體系,尋找起來很是不便。所以對菜單的個性化配置就顯得尤其重要,本篇隨筆就是基於這樣的理念,提供用戶對可見菜單進行一個動態配置,只選本身喜歡、經常使用的菜單顯示出來便可,菜單的配置存儲在數據庫裏面,在不一樣的客戶端體驗都是同樣。本篇隨筆主要介紹實現這樣的功能的一個完整思路,部分代碼邏輯可供參考。html
在咱們有些軟件裏面,咱們可能在界面上頂部放置菜單,也可能在界面的左側放置樹形列表菜單,這種狀況都有可能,本篇摘取其中之一,左側菜單進行一個介紹菜單的配置處理。node
例如咱們在左側根據用戶權限展現相關的菜單信息,動態生成整個列表展現,大體的界面效果以下所示。數據庫
而後在功能列表上提供一個右鍵的菜單進行菜單的刷新、配置管理,以下界面所示。服務器
經過配置功能,咱們讓用戶進入一個配置管理界面,在其中配置顯示本身感興趣的菜單,而後進行保存便可,保存後同時刷新界面的功能菜單顯示。框架
以上幾個界面效果就是爲了介紹整個菜單配置管理的通常過程,之因此把界面效果放在前面介紹,就是可以讓咱們有一個相似原型設計方式的感性認識,瞭解了相關的處理過程,咱們就能夠着手經過編碼的方式來實現這個處理邏輯了。分佈式
上面介紹了大概的界面效果,有了參考,咱們能夠把它的實現思路經過代碼實現出來。ide
首先咱們須要瞭解,用戶配置能夠經過XML保存在本地,也能夠經過數據庫存儲保存在服務器,後者在分佈式的客戶端的時候,能夠到處同樣,這樣就不會形成體驗上的差別,所以咱們這裏採用存儲在數據庫的方案。函數
這個存儲咱們沿用我以前介紹過的配置管理組件(SettingsProvider.net),我在隨筆《Winform開發框架之參數配置管理功能實現-基於SettingsProvider.net的構建》中對它的使用進行了詳細的介紹。工具
這個配置管理組件SettingsProvider.net使用起來也是比較方便的,能夠選擇存儲在本地的對象,也能夠選擇存儲在數據庫的存儲對象。佈局
首先咱們先定義一個存儲的參數類,這個是使用這個組件所必須的存儲對象信息,以下代碼所示。
/// <summary> /// 用來控制人員管理顯示菜單的參數配置 /// </summary> public class UserMenuParameter { [DefaultValue("")] [Description("用戶ID")] public string UserID { get; set; } [Description("用戶設置可見的菜單")] public Dictionary<string, bool> VisibleDict { get; set; } }
須要獲取或存儲這個對象信息的時候,咱們初始化幾個管理類,以下代碼所示。
//參數存儲所需的相關對象 private SettingsProvider settings; private ISettingsStorage store; private UserMenuParameter parameter;
而後在配置管理界面窗體裏面,初始化這幾個對象,以下代碼所示。
// PortableStorage: 在運行程序目錄建立一個setting的文件記錄參數數據 // DatabaseStorage:在數據庫TB_UserParameter表存儲用戶配置參數 store = new DatabaseStorage(LoginUserInfo.ID); settings = new SettingsProvider(store); parameter = settings.GetSettings<UserMenuParameter>();
這樣咱們就能夠根據用戶的ID,獲取對應記錄的信息並轉換爲相關的對象了,若是咱們須要把修改的信息寫會到存儲介質裏面,代碼以下所示。
try { parameter = settings.GetSettings<UserMenuParameter>(); parameter.VisibleDict = dict; parameter.UserID = LoginUserInfo.ID; settings.SaveSettings<UserMenuParameter>(parameter); ProcessDataSaved(sender, e);//觸發外部事件 this.DialogResult = System.Windows.Forms.DialogResult.OK; } catch (Exception ex) { LogHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); return; }
解決了參數的獲取及存儲功能後,咱們須要編寫一個界面來管理用戶的菜單配置,也就是咱們前面介紹的菜單配置管理界面。
咱們這個界面的定義代碼以下所示。
其中參數的數據存儲就是應用了前面介紹的代碼,這裏須要根據用戶的配置項初始化樹形菜單的顯示處理,經過InitTree的函數實現菜單的顯示。
在顯示菜單前,咱們先介紹一下功能菜單顯示的規則,僅當參數存在對應記錄,而且該記錄顯式設置不可見,菜單纔不可見,不然默認菜單是能夠看到的。
這樣確保了,在參數沒有配置前,全部的菜單對當前用戶是可見的,只有用戶設置爲不不可見,該菜單纔不顯示爲不可見。
/// <summary> /// 獲取菜單是否可見。 /// 僅當參數存在對應記錄,而且該記錄顯式設置不可見,菜單纔不可見,不然默認菜單是能夠看到的。 /// </summary> /// <param name="id">菜單ID</param> /// <returns></returns> private bool GetVisibleMenu(string id) { bool result = true; if (parameter != null) { var dict = parameter.VisibleDict; if(dict != null && dict.ContainsKey(id)) { result = dict[id]; } } return result; }
顯示菜單的相關處理邏輯,就是根據上面的判斷,而後肯定是否勾選記錄,以下代碼所示。
存儲用戶勾選的記錄的時候,咱們須要遍歷整個樹節點,判斷勾選了那些選項,而後把它保存數據庫便可。
/// <summary> /// 遞歸獲取選中的樹節點集合 /// </summary> /// <param name="node">樹節點</param> /// <param name="dict">字典集合</param> /// <returns></returns> private Dictionary<string, bool> GetTreeSelection(TreeNode node, Dictionary<string, bool> dict) { if (node.Tag != null) { var check = node.Checked; var menuId = string.Concat(node.Tag); if(!dict.ContainsKey(menuId)) { dict.Add(menuId, check); } } foreach (TreeNode child in node.Nodes) { GetTreeSelection(child, dict); } return dict; }
參數的保存操做以下所示。
/// <summary> /// 保存用戶配置信息 /// </summary> private void btnOK_Click(object sender, EventArgs e) { //獲取用戶勾選的樹列表,存放在字典集合裏面 var dict = new Dictionary<string, bool>(); foreach(TreeNode node in this.treeView1.Nodes) { GetTreeSelection(node, dict); } try { //從新獲取參數信息,並設置新值後保存 parameter = settings.GetSettings<UserMenuParameter>(); parameter.VisibleDict = dict; parameter.UserID = LoginUserInfo.ID; settings.SaveSettings<UserMenuParameter>(parameter); ProcessDataSaved(sender, e);//觸發外部事件 this.DialogResult = System.Windows.Forms.DialogResult.OK; } catch (Exception ex) { LogHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); return; } }
以上處理完成後,咱們在主界面的工具欄右鍵菜單添加一個菜單項,用來進入配置界面的,以下邏輯代碼所示。
private void tool_MenuSetting_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { MenuSetting(); } /// <summary> /// 配置菜單項 /// </summary> private void MenuSetting() { FrmMenuSetting dlg = new FrmMenuSetting(); dlg.OnDataSaved += (s, arg) => { //用戶保存參數後,提示用戶更新樹形列表 InitToolbar(); }; dlg.ShowDialog(); }
這樣界面配置參數並保存後,界面的樹形菜單會及時獲得更新處理。
另外,咱們主界面的樹形列表,也要根據配置參數的信息做相關的調整,若是用戶配置了不顯示某個菜單,那麼主界面也要根據配置參數控制顯示。
以上就是整個菜單列表的動態個性化配置管理的總體思路和實現步驟代碼,主要的界面考量仍是以用戶的視覺來考慮界面的佈局和功能,若是在幾百個菜單項中尋找幾個經常使用的菜單,每次是一個比較耗時無聊的操做,所以提供一個個性化的界面,根據工做狀況的不一樣,顯示一些和本身相關的功能便可。
例若有些狀況下,咱們的菜單顯示,但願經過工具欄的方式進行控制顯示,以下界面效果所示。
那麼配置維護界面仍是差很少,只是咱們控制工具欄的顯示邏輯有所不一樣而已,對於RibbonPage及其功能菜單的動態生成處理以下所示。
本篇隨筆主要仍是但願讀者借鑑配置存儲和菜單個性化管理的思路,具體的邏輯會因用戶界面的不一樣,使用的控件不一樣而有所差別,不過整體思路是一致的便可。
例若有些參數的配置管理,能夠統一使用一個配置管理界面進行維護,如我以前的隨筆介紹的界面功能同樣。
但願本篇隨筆對你有所啓發,感謝耐心閱讀。