今天是大白話系列之C#委託與事件講解的大結局,也是我們最關心的,在日常的MES系統編程中到底怎樣使用這樣的利器,其實我們每天都在使用事件,一個窗體,一個按鈕都包含這事件,只是很少用到自己寫的委託和事件,說白了不知道如何下手,也不知道在什麼樣的場景下應用。
用到事件的地方有很多,這次講解就MES系統開發中我們經常應用的場景。
一、通用控件場景
通用控件有很多,這裏舉最常用的萬能通用分頁控件
【注:】本分頁控件,只是爲了講解使用,並非真分頁控件,還是基於.net控件的分頁
我們先來看場景
我們所看到的這個分頁控件就是這次講解的主角,在日常的編程中,像這樣功能我們用的做多,所以我們必須要把它抽象出來,不能每個頁面都寫分頁邏輯吧。那我們想想到底怎樣去實現這樣的功能呢?怎樣才能讓頁面知道我們按了控件的哪個按鈕呢?這時候讓我們聯想一想委託與事件,一定要聚精會神,叮咚!有了,我們可以把這個控件想象成一個發佈者,而各個頁面就想象成訂閱者,或者是觀察者,當頁面訂閱了分頁控件的事件後,自然就會相應了嘛?
有了思路,我們就開始行動吧!
第一步,我們編寫發佈者代碼,也就是這個控件代碼
public class PageChangeEventArgs : EventArgs
{
private string action = string.Empty;
public string Action
{
get
{
return this.action;
}
set
{
this.action = value;
}
}
public PageChangeEventArgs()
{
}
public PageChangeEventArgs(String paramAction)
{
this.Action = paramAction;
}
}
//發佈者代碼 也就是控件代碼
public partial class UIPageControlsNavigator : System.Web.UI.UserControl
{
//這裏我們聲明一個頁面改變的委託[注:命名一定要規範]
public delegate void PageChangeEventHandler(object sender, PageChangeEventArgs e);
//這裏我們聲明一個事件
public event PageChangeEventHandler PageChange;
//然後以個保護類型的OnPageChange方法
protected virtual void OnPageChange(PageChangeEventArgs e)
{
if (PageChange != null)
{
PageChange(this, e);
}
}
//這裏就是上一講中,具體的觸發函數,這裏變成了一個按鈕觸發事件
protected void lbtnFirst_Click(object sender, EventArgs e)
{
//這時候,訂閱者關心的對象e,也就是觸發的是“首頁”這個按鈕
OnPageChange(new PageChangeEventArgs("First"));
}
protected void lbtnPrevious_Click(object sender, EventArgs e)
{
//這時候,訂閱者關心的對象e,也就是觸發的是“下頁”這個按鈕
OnPageChange(new PageChangeEventArgs("Previous"));
}
protected void lbtnLast_Click(object sender, EventArgs e)
{
OnPageChange(new PageChangeEventArgs("Last"));
}
protected void lbtnNext_Click(object sender, EventArgs e)
{
OnPageChange(new PageChangeEventArgs("Next"));
}
protected void btnSearch_Click(object sender, EventArgs e)
{
if (IsNumber(txtSearchPageCount.Text))
{
OnPageChange(new PageChangeEventArgs("Search"));
}
}
protected void cmbPerPage_SelectedIndexChanged(object sender, EventArgs e)
{
OnPageChange(new PageChangeEventArgs("PageSizeChanged"));
}
....
#region public void BindData(GridView myGridView, IList businessObjects, PageChangeEventArgs e)
/// <summary>
/// 具體控件分頁功能實現
/// </summary>
/// <param name="myGridView">當前Grid控件</param>
/// <param name="businessObjects">數據源</param>
/// <param name="e">事件對象</param>
public void BindData(GridView myGridView, IList businessObjects, PageChangeEventArgs e)
{
// 計算頁面數
if (businessObjects == null)
{
this.RowCount = 0;
}
else
{
this.RowCount = businessObjects.Count;
}
double pageCount = (double)RowCount / this.PageSize;
this.PageCount = (int)Math.Ceiling(pageCount);
myGridView.DataSource = businessObjects;
myGridView.PageSize = this.PageSize;
switch (e.Action)
{
case "PageLoad":
if (CurrentPage > 0)
{
myGridView.PageIndex = CurrentPage - 1;
}
break;
case "First":
myGridView.PageIndex = 0;
myGridView.EditIndex = -1;
break;
case "Previous":
myGridView.PageIndex--;
myGridView.EditIndex = -1;
break;
case "Next":
myGridView.PageIndex++;
myGridView.EditIndex = -1;
break;
case "Last":
myGridView.PageIndex = this.PageCount - 1;
myGridView.EditIndex = -1;
break;
case "PageSizeChanged":
myGridView.PageIndex = 0;
myGridView.EditIndex = -1;
break;
case "Search":
myGridView.PageIndex = int.Parse(txtSearchPageCount.Text) - 1;
break;
case "Refresh":
break;
default:
myGridView.PageIndex = 0;
break;
}
// 頁數不夠了,進行調整
if (myGridView.PageIndex >= this.PageCount)
{
myGridView.PageIndex = this.PageCount == 0 ? 0 : this.PageCount - 1;
}
myGridView.DataBind();
// 獲取按鈕的狀態
this.GetButtonState(myGridView);
}
#endregion
}
當然控件代碼還不值這些,我這裏就列舉出我們委託事件需要的代碼:
然後我們看一下調用頁面的代碼,也就是觀察者,本例中是角色頁面RoleManage.aspx
public partial class RoleManage : BasePage
{
protected void Page_Load(object sender, EventArgs e)
{
//在當前頁面訂閱控件的點擊事件
this.myNavigator.PageChange += new PageChangeEventHandler(this.myNavigator_PageChange);
if (!Page.IsPostBack)
{
}
}
//具體的點擊觸發函數功能,這裏就是控件的分頁
private void myNavigator_PageChange(object sender, PageChangeEventArgs e)
{
this.GetAllRoles(e);
}
private void GetAllRoles(PageChangeEventArgs e)
{
try
{
//角色數據源
roles = roleService.GetAllRoles();
//調用控件的分頁功能函數,這個封裝在分頁控件裏可以,封裝在通用的類庫裏也行
this.myNavigator.BindData(this.grdRole, roles, e);
}
catch (Exception myException)
{
return;
}
}
}
其實原理很簡單,當控件上按下下頁或者其它按鈕的時候,這時候因爲角色管理頁面已經訂閱了這個事件,所以它會執行具體委託的那個實體函數,就這麼簡單
大家了看了可能會頭大,那就自己動手試着做一下,只有做了才能真正的體會到裏面的奧妙,其實和我上一講內容很相識,只是稍微有一點點的變化而已。
先休息一下:
名人名言:
職業生涯:
我總覺得,職業生涯首先要關注的是自己,自己想要什麼?大多數人大概沒想過這個問題,唯一的想法只是——我想要一份工作,我想要一份不錯的薪水,我知道所有人對於薪水的渴望,可是,你想每隔幾年重來一次找工作的過程麼?你想每年都在這種對於工作和薪水的焦急不安中度過麼?不想的話,就好好想清楚。飲鴆止渴,不能因爲口渴就拼命喝毒藥。越是焦急,越是覺得自己需要一份工作,越飢不擇食,越想不清楚,越容易失敗,你的經歷越來越差,下一份工作的人看着你的簡歷就皺眉頭。於是你越喝越渴,越渴越喝,陷入惡性循環。最終只能哀嘆世事不公或者生不逢時,只能到天涯上來發泄一把,在失敗者的共鳴當中尋求一點心理平衡罷了。大多數人都有生存壓力,我也是,有生存壓力就會有很多焦慮,積極的人會從焦慮中得到動力,而消極的人則會因爲焦慮而迷失方向。所有人都必須在壓力下做出選擇,這就是世道,你喜歡也罷不喜歡也罷。
二、業務控件場景
大家在做MES系統的時候,50%的時候是在複製黏貼,甚至有的時候有些邏輯老是複製到這裏,然後複製到那裏,當然起初的時候感覺很快,也不用動腦子ctrl+c,ctrl+v結束,但是到後來邏輯改了,那時候就像沒頭蒼蠅似的,早就忘了到底有多少地方用到這些邏輯,所以往往到BUG發生的時候,才恍然大悟“哦!原來這裏忘了改了!”等等。我並不反對大家ctrl+c,ctrl+v,但是在享受這樣的快捷之後,騰出時間再來重構一下,看看這時候能否用是否能抽象呀?用設計模式?符不符合00的設計原則?不然你就是編10年的軟件,又能得到什麼樣的提高!又扯遠了。。。
接下來,我們具體來看場景:
這是一個工作流審批用戶控件,做MES系統的其實經常會和這個打交道,然而我們把這個邏輯封裝成一個控件,那我們在今後維護上將會減輕很多工作量
這裏我只介紹這控件技術上我們用到的委託和事件的代碼
{
//EventHandler是微軟默認的委託,在本例中我們直接就用EventHandler來表示委託,當然它的參數是Sender,e
public event EventHandler Preview;
public event EventHandler Submit;
public event EventHandler FMOK;
public event EventHandler FMProgress;
public event EventHandler FMSave;
...
//提交按鈕事件
protected void btnSubmit_Click(object sender, EventArgs e)
{
try
{
//觸發我們定義的事件
Submit(sender, e);
}
catch (Exception ex)
{
...
}
}
...
}
然後我們到訂閱這個事件的頁面上看一下代碼
{
protected void Page_Load(object sender, EventArgs e)
{
...
//在次頁面中訂閱審批控件的提交按鈕事件
ApprovalResults1.Submit += new EventHandler(ApprovalResults1_Submit);
}
//具體的提交事件功能函數
public void ApprovalResults1_Submit(object sender, EventArgs e)
{
try
{
}
catch (Exception ex)
{
}
finally
{
}
}
}
這樣我想大家都理解了,當審批控件點擊提交按鈕,其實訪問的就是訂閱者頁面的功能函數。
其實委託事件應用的場景還有很多,它就是觀察者模式的提煉。
到此委託與事件講解的大白話系列到此完畢,我非常希望大家能看了我的文章後能有點收穫。
今後我會寫更多的大白話系列,讓抽象的東西更能讓大家理解【注:因爲要想些通俗的例子,所以更新的速度有點慢】
首頁推薦不能放,我就放這裏好了
推薦2篇文章,是關於人生的