大白話系列之C#委託與事件講解大結局

今天是大白話系列之C#委託與事件講解的大結局,也是我們最關心的,在日常的MES系統編程中到底怎樣使用這樣的利器,其實我們每天都在使用事件,一個窗體,一個按鈕都包含這事件,只是很少用到自己寫的委託和事件,說白了不知道如何下手,也不知道在什麼樣的場景下應用。

用到事件的地方有很多,這次講解就MES系統開發中我們經常應用的場景。
一、通用控件場景
通用控件有很多,這裏舉最常用的萬能通用分頁控件
【注:】本分頁控件,只是爲了講解使用,並非真分頁控件,還是基於.net控件的分頁
我們先來看場景

我們所看到的這個分頁控件就是這次講解的主角,在日常的編程中,像這樣功能我們用的做多,所以我們必須要把它抽象出來,不能每個頁面都寫分頁邏輯吧。那我們想想到底怎樣去實現這樣的功能呢?怎樣才能讓頁面知道我們按了控件的哪個按鈕呢?這時候讓我們聯想一想委託與事件,一定要聚精會神,叮咚!有了,我們可以把這個控件想象成一個發佈者,而各個頁面就想象成訂閱者,或者是觀察者,當頁面訂閱了分頁控件的事件後,自然就會相應了嘛?

有了思路,我們就開始行動吧!

第一步,我們編寫發佈者代碼,也就是這個控件代碼

 

ExpandedBlockStart.gif代碼
   //和我們上一講講的一樣,我們先定義訂閱者所感興趣的對象,這裏我們將它抽象成Action,也就是首頁、下頁、上頁之類的動作
    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

ExpandedBlockStart.gif代碼
    //角色管理頁面代碼類
    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系統的其實經常會和這個打交道,然而我們把這個邏輯封裝成一個控件,那我們在今後維護上將會減輕很多工作量

這裏我只介紹這控件技術上我們用到的委託和事件的代碼

 

ExpandedBlockStart.gif代碼
public partial class ApprovalResults : System.Web.UI.UserControl
{
  
//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)
     {
     ...
     }
  }

  ...
}

 

然後我們到訂閱這個事件的頁面上看一下代碼

 

ExpandedBlockStart.gif代碼
    public partial class Preview : BasePage
    {
        
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
            {             
            }
        }
    }

 

 

這樣我想大家都理解了,當審批控件點擊提交按鈕,其實訪問的就是訂閱者頁面的功能函數。

其實委託事件應用的場景還有很多,它就是觀察者模式的提煉。

到此委託與事件講解的大白話系列到此完畢,我非常希望大家能看了我的文章後能有點收穫。

今後我會寫更多的大白話系列,讓抽象的東西更能讓大家理解【注:因爲要想些通俗的例子,所以更新的速度有點慢】

 

 

 

首頁推薦不能放,我就放這裏好了

大白話系列之C#委託與事件講解(序言)

大白話系列之C#委託與事件講解(一)  

大白話系列之C#委託與事件講解(二)

大白話系列之C#委託與事件講解(三)

 

 

推薦2篇文章,是關於人生的

 爲什麼我們做不到【領導篇】

 爲什麼我們做不到【員工篇】

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章