在Winform系統開發中,為了對系統的工具欄/菜單進行動態的控制,我們對系統的工具欄/菜單進行動態配置,這樣可以把系統的功能彈性發揮到極致。通過動態工具欄/菜單的配置方式,我們可以很容易的為系統新增所需的功能,通過許可權分配的方式,可以更有效的管理系統的菜單分配到不同的角色用戶,也就是插件化的處理方... ...
在Winform系統開發中,為了對系統的工具欄/菜單進行動態的控制,我們對系統的工具欄/菜單進行動態配置,這樣可以把系統的功能彈性發揮到極致。通過動態工具欄/菜單的配置方式,我們可以很容易的為系統新增所需的功能,通過許可權分配的方式,可以更有效的管理系統的菜單分配到不同的角色用戶,也就是插件化的處理方式。
1、動態菜單的控制
我們一般的應用系統裡面,由於系統是面向不同類型的用戶,我們所看到的菜單會越來越多,多一點的甚至上百個,但是我們實際工作接觸的菜單可能就是那麼幾個,那麼對於這種龐大的菜單體系,尋找起來非常不便。因此對菜單的個性化配置就顯得尤為重要。
但在我們開發的時候,為了方便調試和測試基礎功能,有時候有需要直接在Ribbon工具欄或者菜單中固定一些功能的入口,以便快速開發某些常見功能,那麼我們可以在系統中增加一個變數來控制動態展示還是採用靜態工具欄/菜單的方式。
因此我們在主窗體中使用菜單/工具欄,分為了預設的靜態模式(方便測試)和動態模式(實際應用)。
以上圖示是預設的一些基礎入口,我們可以先具體測試某些功能,這樣不會打斷實際的開發工作,而在系統部署給客戶的時候,採用動態模式構建的工具欄/菜單,用戶在登錄的時候,首先清空預設菜單,在載入擁有的菜單/工具欄,這樣就不會相互影響。
我們在程式的主視窗,增加一個變數來控制是否動態即可,預設為false,也就是靜態控制項模式,開發完成後,部署的時候,把它改為True即可,如下代碼。
/// <summary> /// 程式主界面 /// </summary> public partial class MainForm : RibbonForm { /// <summary> /// 是否標記為動態生成頂部按鈕欄,從資料庫讀取動態菜單信息。 /// </summary> private bool useRemoteMenu = false;
因此我們可以根據這個開關變數來處理菜單的載入處理,如下代碼函數所示是處理工具欄、菜單的載入邏輯。
/// <summary> /// 初始化左側功能菜單樹列表 /// </summary> private void InitToolbar() { //如果標記為動態生成,那麼預設的菜單將清空 if (useRemoteMenu) { //初始化Ribbon控制類 if (ribbonHelper == null) { ribbonHelper = new RibbonPageHelper(this, ref this.ribbonControl); } ribbonHelper.ClearAllPages();//預設的菜單清空 ribbonHelper.AddPages();//動態創建界面菜單對象 } //重新加入應用程式菜單,否則訪問出錯 this.applicationMenu1.ItemLinks.Clear(); this.applicationMenu1.AddItems(new DevExpress.XtraBars.BarItem[] { this.menu_QuitSystem, this.menu_Relogin }); //根據許可權屏蔽菜單對象 InitAuthorizedUI(); if (this.ribbonControl.Pages.Count > 0) { ribbonControl.SelectedPage = ribbonControl.Pages[0]; } }
其中 RibbonPageHelper 輔助類就是用來動態構建Ribbon工具欄的,如果是靜態,則預設採用設計時刻的工具按鈕即可。
其中ClearAllPages就是清空按鈕。
/// <summary> /// 清空所有按鈕 /// </summary> public void ClearAllPages() { if(this.control != null && this.control.Pages != null) { this.control.Pages.Clear(); } }
而動態構建的工具欄按鈕,就是根據用戶的角色身份所控制的按鈕處理的。
而構建菜單/工具欄按鈕的時候,我們主要就是創建工具欄按鈕的名稱、圖標、以及響應的事件即可,如下代碼所示。
/// <summary> /// 動態創建Ribbon的按鈕項目 /// </summary> /// <param name="menuInfo">菜單信息</param> /// <returns></returns> private BarButtonItem CreateButonItem(MenuNodeInfo menuInfo) { //添加功能按鈕(三級菜單) var button = new BarButtonItem(); button.PaintStyle = BarItemPaintStyle.CaptionGlyph; button.LargeGlyph = LoadIcon(menuInfo); button.Glyph = LoadIcon(menuInfo); button.Name = menuInfo.Id; button.Caption = menuInfo.Name; button.Tag = menuInfo.WinformType; button.ItemClick += (sender, e) => { if (button.Tag != null && !string.IsNullOrEmpty(button.Tag.ToString())) { LoadPlugInForm(string.Concat(button.Tag)); } else { MessageDxUtil.ShowTips(button.Caption); } }; return button; }
其中 LoadPlugInForm 函數就是我們載入菜單處理的邏輯,一般就是根據配置信息動態構建出一個窗體即可。
2、動態菜單信息的解析
因此我們需要瞭解動態菜單的項目中,具體的配置信息是什麼,才知道如何具體使用反射的方法,來構建出一個窗體的實例顯示。
如上圖所示的內容,前面部分為窗體類的全局名稱,而後面是窗體所在的程式集名稱,這樣我們根據程式集的名稱,菜單或者按鈕的單擊事件中載入窗體類顯示即可。我們一般以逗號分開兩個部分,如果是當前程式集,也可以忽略,有系統自動解析加上即可。
string[] itemArray = typeName.Split(new char[]{',',';'});
然後根據內容解析窗體類和具體的程式集路徑即可。
string type = itemArray[0].Trim(); string filePath = (itemArray.Length > 1) ? itemArray[1].Trim() : Assembly.GetExecutingAssembly().GetName().Name;//必須是相對路徑
最後稍微處理下,通過具體路徑構建處理即可。
//從程式集中載入窗體類,設置為多文檔的模式 string dllFullPath = Path.Combine(Application.StartupPath, filePath); var tempAssembly = Assembly.LoadFrom(dllFullPath); if (tempAssembly != null) { Type objType = tempAssembly.GetType(type); if (objType != null) { LoadMdiForm(this.mainForm, objType, isShowDialog); } }
多窗體的顯示,先判斷是否存在,如果不存在則創建,存在則激活即可。
if (isShowDialog) { tableForm.ShowDialog(); } else { tableForm.MdiParent = mainDialog; tableForm.Show(); } tableForm.BringToFront(); tableForm.Activate();
這樣就是動態工具欄、菜單的處理邏輯了。

轉載請註明出處:撰寫人:伍華聰 http://www.iqidi.com