隨筆背景:在很多時候,很多入門不久的朋友都會問我:我是從其他語言轉到C#開發的,有沒有一些基礎性的資料給我們學習學習呢,你的框架感覺一下太大了,希望有個循序漸進的教程或者視頻來學習就好了。
其實也許我們每天面對的太多東西了,覺得很多都稀松平常了,即使很細微的地方,可能我們都已經形成習慣了。反過來,如果我們切換到其他領域,如IOS、android,那么開始我們可能對里面很多設計的規則不甚了解,開始可能也是一頭霧水。
本篇繼續上一篇《循序漸進開發WinForm項目(3)--Winform界面層的項目設計》,繼續介紹如何循序漸進開發Winform項目,繼續介紹Winform界面模塊如何整合到主體項目工程里面,進行使用等操作,使得我們逐漸了解一個完整的開發方案過程。
1、窗體界面的集成使用
上篇介紹了如何利用工具進行Winform界面層窗體的快速生成,並進行適當的調整,已達到合理布局,顯示美觀等的效果,本篇繼續這一主題介紹下去,上篇我們開發好的獨立界面模塊,如何在主體項目中集成使用呢?
首先我們把生成的界面層DLL復制到項目工程中,然后在主項目工程中添加相關的應用,如下所示。
然后,我們需要做的就是,在主體界面模塊里面添加一個功能按鈕的入口,如下所示是我在我的框架界面啟動模塊里面添加一個按鈕的效果。
然后在按鈕的單擊事件里面,添加下面的代碼即可。
private void tool_Customer_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { ChildWinManagement.LoadMdiForm(this, typeof(WHC.TestProject.UI.FrmCustomer)); }
其中ChildWinManagement是公用類庫里面一個輔助類,用來在多文檔的情況下進行窗體的展示,傳入一個MDI的Parent的窗體對象引用,另外一個是構造顯示的窗體類型,它會根據類型來判斷是否已經實例化了,如果存在就打開,否則就創建一個新的窗體病顯示出來主界面里面。
啟動界面,后看到的效果如下所示(我們在后台添加一些測試數據后)。
雙擊數據出來的編輯界面如下所示。
這樣,我們在還沒有添加任何代碼和邏輯實現的情況下,基本的界面已經出來了,而且相關的數據存儲和顯示的功能已經存在,我們所需要做的就只是細化里面的內容即可。
2、窗體界面的在插件化框架的集成使用
第一節中介紹的是傳統方式的界面模塊的繼承,開發框架本身也還提供了另外一種方式的界面模塊集成方式,插件化的模塊化集成。我們通過把相關的DLL復制到運行的目錄下,並且在數據庫里面配置好相關的Winform模塊信息后,就可以在主界面中調用出來是用來。
關於插件化的框架實現的介紹,大家可以看看我前面寫的一篇博客文章《Winform開發框架之插件化應用框架實現》。
首先我們配置菜單的時候,登陸權限管理系統,添加相關的菜單項目,如下所示。當然,如果你有自己的菜單管理模塊,自己通過自己的手工設置好相關的信息即可。
好,搞定菜單的動態配置后,我們重新登陸下系統的主界面,看看有無變化了。
從主界面的Ribbon工具欄,我們可以看到,里面已經新增了一個客戶管理(紅色部分)的內容了,這個位置就是我們剛才新增菜單的位置。單擊菜單按鈕,那么就會展現出來客戶管理的內容了。
整個主界面框架,加上打開的客戶管理界面,整體的效果是一個多文檔的界面效果。
3、集成登陸用戶信息
前面幾篇的隨筆,主要就是介紹給我們認識如何快速開發一個模塊,並且集成到系統框架里面進行使用,我們甚至還沒有開始編碼,就已經給我們處理好很多細節上的東西,基本上就已經完成一個業務小模塊的展示工作了。
完成本文的前面兩個小節,不知道你們有沒有發現,我們好像還沒有真正的整合登陸的用戶信息呢?在獨立的系統模塊開發過程中,我們如何整合登陸的用戶信息呢?
我們重新回到開發的業務模塊的界面項目里面看看原來的編輯界面代碼。
這里面對於保存新增的數據,我們調整一下,把它的創建的人員和時間在代碼FrmEditCustomer.cs里面調整成合理的代碼,記錄人員和當前時間。
/// <summary> /// 編輯或者保存狀態下取值函數 /// </summary> /// <param name="info"></param> private void SetInfo(CustomerInfo info) { info.Name = txtName.Text; info.Age = txtAge.Value.ToString().ToInt32(); } /// <summary> /// 新增狀態下的數據保存 /// </summary> /// <returns></returns> public override bool SaveAddNew() { CustomerInfo info = tempInfo;//必須使用存在的局部變量,因為部分信息可能被附件使用 SetInfo(info); info.CreateTime = DateTime.Now; info.Creator = LoginUserInfo.ID.ToString();//為了更好管理,我們這里存儲用戶的ID,而非名稱 try { #region 新增數據 bool succeed = BLLFactory<Customer>.Instance.Insert(info); if (succeed) { //可添加其他關聯操作 return true; } #endregion } catch (Exception ex) { LogTextHelper.Error(ex); MessageDxUtil.ShowError(ex.Message); } return false; }
其中紅色部分就是我們新增的內容,我在代碼里面存儲當前登陸用戶的ID:LoginUserInfo.ID.ToString()。
這里的LoginUserInfo是窗體基類的一個屬性,這個屬性通過兩種方式獲得,一個是通過用戶在調用窗體顯示前進行指定,一種是通過基類自動把緩存里面的用戶對象賦值。
如下面的代碼就是界面基類BaseForm的部分代碼。
namespace WHC.Framework.BaseUI { /// <summary> /// 常規界面基類 /// </summary> public partial class BaseForm : DevExpress.XtraEditors.XtraForm, IFunction { public event EventHandler OnDataSaved;//子窗體數據保存的觸發 public BaseForm() { InitializeComponent(); //為了保證一些界面控件的權限控制和身份確認,以及簡化操作,在界面初始化的時候,從緩存里面內容(如果存在的話) //繼承的子模塊,也可以通過InitFunction()進行指定用戶相關信息 this.LoginUserInfo = Cache.Instance["LoginUserInfo"] as LoginUserInfo; this.FunctionDict = Cache.Instance["FunctionDict"] as Dictionary<string, string>; }
這些用戶和功能的信息來源於登陸主界面的時候,我們把它們進行了緩存,方便基類窗體進行獲取。
Portal.gc.LoginUserInfo = Portal.gc.ConvertToLoginUser(info); Cache.Instance.Add("LoginUserInfo", Portal.gc.LoginUserInfo);//緩存用戶信息,方便后續處理 Cache.Instance.Add("FunctionDict", Portal.gc.FunctionDict);//緩存權限信息,方便后續使用
第二種方式指定當前用戶信息的步驟,是通過基類窗體的InitFunction函數進行指定。
/// <summary> /// 初始化權限控制信息 /// </summary> public void InitFunction(LoginUserInfo userInfo, Dictionary<string, string> functionDict) { if (userInfo != null) { this.LoginUserInfo = userInfo; } if (functionDict != null && functionDict.Count > 0) { this.FunctionDict = functionDict; } }
手工指定當前用戶信息的調用代碼如下所示。
private void btnAddNew_Click(object sender, EventArgs e) { FrmEditCustomer dlg = new FrmEditCustomer(); dlg.InitFunction(base.LoginUserInfo, base.FunctionDict);//該步驟省略也可以,用戶信息以通過基類緩存進行獲取 if (DialogResult.OK == dlg.ShowDialog()) { BindData(); } }
一般情況下,我們建議采用第一種,不用多余的代碼進行設置指定,只需要在登錄的時候,把它放到緩存里面即可,這樣界面基類實例化的時候,就會自動獲取用戶信息了,這個操作類似於Web領域里面的Session操作,只要存儲/獲取的鍵值保存一致即可。
好了,我們前面說到,保存的時候,是保存當前用戶的ID信息,那么我們在列表展示的時候,默認就會展示用戶的ID信息而已,得到的界面效果如下所示。
我們為了更好展示內容,就需要對用戶ID的數據進行轉義。
由於DevExpress有這樣對每行記錄進行轉義的操作,我們在列表界面上添加一個轉義函數。
this.winGridViewPager1.gridView1.CustomColumnDisplayText += new DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventHandler(gridView1_CustomColumnDisplayText);
數據轉義函數里面涉及到對權限系統模塊的引用(我們需要把ID轉義為FullName(用戶全名)),我們把權限模塊的DLL引用包含進來即可(因為權限管理模塊是所有界面模塊都可以使用的)。
然后在這個函數里面對當前的Creator進行轉義。
void gridView1_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e) { if (e.Column.ColumnType == typeof(DateTime)) { string columnName = e.Column.FieldName; if (e.Value != null) { if (Convert.ToDateTime(e.Value) <= Convert.ToDateTime("1900-1-1")) { e.DisplayText = ""; } else { e.DisplayText = Convert.ToDateTime(e.Value).ToString("yyyy-MM-dd HH:mm");//yyyy-MM-dd } } } else if (e.Column.FieldName == "Creator") { if (e.Value != null) { e.DisplayText = BLLFactory<User>.Instance.GetFullNameByID(e.Value.ToString().ToInt32()); } } }
然后復制文件,重新運行主程序即可看到如下界面所示。
至此,我們本小節已經完成了,登陸用戶信息的記錄和轉義的操作了,當然我們系統模塊里面,可能還有很多地方需要用到用戶信息的或者角色信息的,這個例子只是一個拋磚引玉的操作。
循序漸進開發WInform項目--系列文章導引:
《循序漸進開發WinForm項目(4)--Winform界面模塊的集成使用》
《循序漸進開發WinForm項目(3)--Winform界面層的項目設計》
《循序漸進開發WinForm項目(1) --數據庫設計和項目框架的生成》