隨筆背景:在很多時候,很多入門不久的朋友都會問我:我是從其他語言轉到C#開發(fā)的,有沒有一些基礎性的資料給我們學習學習呢,你的框架感覺一下太大了,希望有個循序漸進的教程或者視頻來學習就好了。
其實也許我們每天面對的太多東西了,覺得很多都稀松平常了,即使很細微的地方,可能我們都已經形成習慣了。反過來,如果我們切換到其他領域,如IOS、android,那么開始我們可能對里面很多設計的規(guī)則不甚了解,開始可能也是一頭霧水。
本篇繼續(xù)上一篇《循序漸進開發(fā)WinForm項目(3)--Winform界面層的項目設計》,繼續(xù)介紹如何循序漸進開發(fā)Winform項目,繼續(xù)介紹Winform界面模塊如何整合到主體項目工程里面,進行使用等操作,使得我們逐漸了解一個完整的開發(fā)方案過程。
1、窗體界面的集成使用
上篇介紹了如何利用工具進行Winform界面層窗體的快速生成,并進行適當?shù)恼{整,已達到合理布局,顯示美觀等的效果,本篇繼續(xù)這一主題介紹下去,上篇我們開發(fā)好的獨立界面模塊,如何在主體項目中集成使用呢?
首先我們把生成的界面層DLL復制到項目工程中,然后在主項目工程中添加相關的應用,如下所示。

然后,我們需要做的就是,在主體界面模塊里面添加一個功能按鈕的入口,如下所示是我在我的框架界面啟動模塊里面添加一個按鈕的效果。

然后在按鈕的單擊事件里面,添加下面的代碼即可。
private void tool_Customer_ItemClick(object sender, DevExpress.XtraBars.ItemClickEventArgs e) { ChildWinManagement.LoadMdiForm(this, typeof(WHC.TestProject.UI.FrmCustomer)); }
其中ChildWinManagement是公用類庫里面一個輔助類,用來在多文檔的情況下進行窗體的展示,傳入一個MDI的Parent的窗體對象引用,另外一個是構造顯示的窗體類型,它會根據(jù)類型來判斷是否已經實例化了,如果存在就打開,否則就創(chuàng)建一個新的窗體病顯示出來主界面里面。
啟動界面,后看到的效果如下所示(我們在后臺添加一些測試數(shù)據(jù)后)。

雙擊數(shù)據(jù)出來的編輯界面如下所示。

這樣,我們在還沒有添加任何代碼和邏輯實現(xiàn)的情況下,基本的界面已經出來了,而且相關的數(shù)據(jù)存儲和顯示的功能已經存在,我們所需要做的就只是細化里面的內容即可。
2、窗體界面的在插件化框架的集成使用
第一節(jié)中介紹的是傳統(tǒng)方式的界面模塊的繼承,開發(fā)框架本身也還提供了另外一種方式的界面模塊集成方式,插件化的模塊化集成。我們通過把相關的DLL復制到運行的目錄下,并且在數(shù)據(jù)庫里面配置好相關的Winform模塊信息后,就可以在主界面中調用出來是用來。
關于插件化的框架實現(xiàn)的介紹,大家可以看看我前面寫的一篇博客文章《Winform開發(fā)框架之插件化應用框架實現(xiàn)》。
首先我們配置菜單的時候,登陸權限管理系統(tǒng),添加相關的菜單項目,如下所示。當然,如果你有自己的菜單管理模塊,自己通過自己的手工設置好相關的信息即可。

好,搞定菜單的動態(tài)配置后,我們重新登陸下系統(tǒng)的主界面,看看有無變化了。

從主界面的Ribbon工具欄,我們可以看到,里面已經新增了一個客戶管理(紅色部分)的內容了,這個位置就是我們剛才新增菜單的位置。單擊菜單按鈕,那么就會展現(xiàn)出來客戶管理的內容了。
整個主界面框架,加上打開的客戶管理界面,整體的效果是一個多文檔的界面效果。

3、集成登陸用戶信息
前面幾篇的隨筆,主要就是介紹給我們認識如何快速開發(fā)一個模塊,并且集成到系統(tǒng)框架里面進行使用,我們甚至還沒有開始編碼,就已經給我們處理好很多細節(jié)上的東西,基本上就已經完成一個業(yè)務小模塊的展示工作了。
完成本文的前面兩個小節(jié),不知道你們有沒有發(fā)現(xiàn),我們好像還沒有真正的整合登陸的用戶信息呢?在獨立的系統(tǒng)模塊開發(fā)過程中,我們如何整合登陸的用戶信息呢?
我們重新回到開發(fā)的業(yè)務模塊的界面項目里面看看原來的編輯界面代碼。

這里面對于保存新增的數(shù)據(jù),我們調整一下,把它的創(chuàng)建的人員和時間在代碼FrmEditCustomer.cs里面調整成合理的代碼,記錄人員和當前時間。
/// <summary>
/// 編輯或者保存狀態(tài)下取值函數(shù)
/// </summary>
/// <param name="info"></param>
private void SetInfo(CustomerInfo info)
{
info.Name = txtName.Text;
info.Age = txtAge.Value.ToString().ToInt32();
}
/// <summary>
/// 新增狀態(tài)下的數(shù)據(jù)保存
/// </summary>
/// <returns></returns>
public override bool SaveAddNew()
{
CustomerInfo info = tempInfo;//必須使用存在的局部變量,因為部分信息可能被附件使用
SetInfo(info);
info.CreateTime = DateTime.Now;
info.Creator = LoginUserInfo.ID.ToString();//為了更好管理,我們這里存儲用戶的ID,而非名稱
try
{
#region 新增數(shù)據(jù)
bool succeed = BLLFactory<Customer>.Instance.Insert(info);
if (succeed)
{
//可添加其他關聯(lián)操作
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>
/// 常規(guī)界面基類
/// </summary>
public partial class BaseForm : DevExpress.XtraEditors.XtraForm, IFunction
{
public event EventHandler OnDataSaved;//子窗體數(shù)據(jù)保存的觸發(fā)
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);//緩存用戶信息,方便后續(xù)處理
Cache.Instance.Add("FunctionDict", Portal.gc.FunctionDict);//緩存權限信息,方便后續(xù)使用
第二種方式指定當前用戶信息的步驟,是通過基類窗體的InitFunction函數(shù)進行指定。
/// <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信息而已,得到的界面效果如下所示。

我們?yōu)榱烁谜故緝热?,就需要對用戶ID的數(shù)據(jù)進行轉義。
由于DevExpress有這樣對每行記錄進行轉義的操作,我們在列表界面上添加一個轉義函數(shù)。
this.winGridViewPager1.gridView1.CustomColumnDisplayText += new DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventHandler(gridView1_CustomColumnDisplayText);
數(shù)據(jù)轉義函數(shù)里面涉及到對權限系統(tǒng)模塊的引用(我們需要把ID轉義為FullName(用戶全名)),我們把權限模塊的DLL引用包含進來即可(因為權限管理模塊是所有界面模塊都可以使用的)。
然后在這個函數(shù)里面對當前的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());
}
}
}
然后復制文件,重新運行主程序即可看到如下界面所示。

至此,我們本小節(jié)已經完成了,登陸用戶信息的記錄和轉義的操作了,當然我們系統(tǒng)模塊里面,可能還有很多地方需要用到用戶信息的或者角色信息的,這個例子只是一個拋磚引玉的操作。
循序漸進開發(fā)WInform項目--系列文章導引:
循序漸進開發(fā)WinForm項目(6)--開發(fā)使用混合式Winform模塊
循序漸進開發(fā)WinForm項目(5)--Excel數(shù)據(jù)的導入導出操作
循序漸進開發(fā)WinForm項目(4)--Winform界面模塊的集成使用
循序漸進開發(fā)WinForm項目(3)--Winform界面層的項目設計
循序漸進開發(fā)WinForm項目(2)--項目代碼的分析
循序漸進開發(fā)WinForm項目(1) --數(shù)據(jù)庫設計和項目框架的生成