五月综合缴情婷婷六月,色94色欧美sute亚洲线路二,日韩制服国产精品一区,色噜噜一区二区三区,香港三级午夜理伦三级三

您現(xiàn)在的位置: 365建站網(wǎng) > 365文章 > C#委托和事件傳遞參數(shù)(Delegate、Event、EventHandler、EventArgs)

C#委托和事件傳遞參數(shù)(Delegate、Event、EventHandler、EventArgs)

文章來源:365jz.com     點擊數(shù):4678    更新時間:2018-06-06 09:00   參與評論

委托

當(dāng)要把方法作為實參傳送給其他方法的形參時,形參需要使用委托。委托是一個類型,是一個函數(shù)指針類型,這個類型將該委托的實例化對象所能指向的函數(shù)的細(xì)節(jié)封裝起來了,即規(guī)定了所能指向的函數(shù)的簽名,也就是限制了所能指向的函數(shù)的參數(shù)和返回值。當(dāng)實例化委托的時候,委托對象會指向某一個匹配的函數(shù),實質(zhì)就是將函數(shù)的地址賦值給了該委托的對象,然后就可以通過該委托對象來調(diào)用所指向的函數(shù)了。

定義委托

語法如下:

delegate  result-type   Identifier ([parameters]);

說明:

result-type:返回值的類型,和方法的返回值類型一致

Identifier:委托的名稱

parameters:參數(shù),要引用的方法帶的參數(shù)

小結(jié):

當(dāng)定義了委托之后,該委托的對象一定可以而且也只能指向該委托所限制的函數(shù)。即參數(shù)的個數(shù)、類型、順序都要匹配,返回值的類型也要匹配。

因為定義委托相當(dāng)于是定義一個新類,所以可以在定義類的任何地方定義委托,既可以在一個類的內(nèi)部定義,那么此時就要通過該類的類名來調(diào)用這個委托(委托必須是public、internal),也可以在任何類的外部定義,那么此時在命名空間中與類的級別是一樣的。

聲明一個基于某個委托的事件

Event delegateName  eventName;

eventName不是一個類型,而是一個具體的對象,這個具體的對象只能在類A內(nèi)定義而不能在類A外定義。

在類A中定義一個觸發(fā)該事件的方法

ReturnType  FunctionName([parameters])
{
     ……
If(eventName != null)
{
eventName([parameters]);
或者eventName.Invoke([parameters]);
}
……
}

觸發(fā)事件之后,事件所指向的函數(shù)將會被執(zhí)行。這種執(zhí)行是通過事件名稱來調(diào)用的,就像委托對象名一樣的。

觸發(fā)事件的方法只能在A類中定義,事件的實例化,以及實例化之后的實現(xiàn)體都只能在A類外定義。

程序?qū)嵗?/strong>

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace DelegateStudy
{
    public delegate void DelegateClick (int a);
    public class butt
    {
        public event DelegateClick Click;
        public void OnClick(int a)
        {
            if(Click != null)
                Click.Invoke(a);
               //Click(a);//這種方式也是可以的
            MessageBox.Show("Click();");
        }
    }
    class Frm
    {
        public static void Btn_Click(int a)
        {
            for (long i = 0; i < a; i++)
                Console.WriteLine(i.ToString());
        }
        static void Main(string[] args)
        {
            butt b = new butt();
           //在委托中,委托對象如果是null的,直接使用+=符號,會報錯,但是在事件中,初始化的時候,只能用+=
            b.Click += new DelegateClick (Fm_Click); //事件是基于委托的,所以委托推斷一樣適用,下面的語句一樣有效:b.Click += Fm_Click;
            //b.Click(10);錯誤:事件“DelegateStudy.butt.Click”只能出現(xiàn)在 += 或 -= 的左邊(從類型“DelegateStudy.butt”中使用時除外)
            b.OnClick (10000);                        
            MessageBox.Show("sd234234234");
            Console.ReadLine();
        }
   }
}


控件事件委托EventHandler

在控件事件中,有很多的委托,在這里介紹一個最常用的委托EventHandler,.NET Framework中控件的事件很多都基于該委托,EventHandler委托已在.NET Framework中定義了。它位于System命名空間:

Public delegate void EventHandler(object sender,EventArgs e);

委托EventHandler參數(shù)和返回值

事件最終會指向一個或者多個函數(shù),函數(shù)要與事件所基于的委托匹配。事件所指向的函數(shù)(事件處理程序)的命名規(guī)則:按照約定,事件處理程序應(yīng)遵循“object_event”的命名約定。object就是引發(fā)事件的對象,而event就是被引發(fā)的事件。從可讀性來看,應(yīng)遵循這個命名約定。

首先,事件處理程序總是返回void,事件處理程序不能有返回值。其次是參數(shù),只要是基于EventHandler委托的事件,事件處理程序的參數(shù)就應(yīng)是object和EventArgs類型:

第一個參數(shù)接收引發(fā)事件的對象,比如當(dāng)點擊某個按鈕的時候,這個按鈕要觸發(fā)單擊事件最終執(zhí)行這個函數(shù),那么就會把當(dāng)前按鈕傳給sender,當(dāng)有多個按鈕的單擊事件都指向這個函數(shù)的時候,sender的值就取決于當(dāng)前被單擊的那個按鈕,所以可以為幾個按鈕定義一個按鈕單擊處理程序,接著根據(jù)sender參數(shù)確定單擊了哪個按鈕:

if(((Button)sender).Name =="buttonOne")

第二個參數(shù)e是包含有關(guān)事件的其他有用信息的對象。

控件事件的其他委托

控件事件還有其他的委托,比如在窗體上有與鼠標(biāo)事件關(guān)聯(lián)的委托:

Public delegate void MouseEventHandler(object sender,MouseEventArgs e);

public event MouseEventHandler MouseDown;

this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown);

private void Form1_MouseDown(object sender, MouseEventArgs e){};

MouseDown事件使用MouseDownEventArgs,它包含鼠標(biāo)的指針在窗體上的的X和Y坐標(biāo),以及與事件相關(guān)的其他信息。

控件事件中,一般第一個參數(shù)都是object sender,第二個參數(shù)可以是任意類型,不同的委托可以有不同的參數(shù),只要它派生于EventArgs即可。

程序?qū)嵗?/strong>

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
 
namespace SecondChangeEvent1
{
    // 該類用來存儲關(guān)于事件的有效信息外,
    // 還用來存儲額外的需要傳給訂閱者的Clock狀態(tài)信息
    public class TimeInfoEventArgs : EventArgs
    {
        public TimeInfoEventArgs(int hour,int minute,int second)
        {
            this.hour = hour;
            this.minute = minute;
            this.second = second;
        }
        public readonly int hour;
        public readonly int minute;
        public readonly int second;
    }
 
    // 定義名為SecondChangeHandler的委托,封裝不返回值的方法,
    // 該方法帶參數(shù),一個clock類型對象參數(shù),一個TimeInfoEventArgs類型對象
    public delegate void SecondChangeHandler(
       object clock,
       TimeInfoEventArgs timeInformation
    );
    // 被其他類觀察的鐘(Clock)類,該類發(fā)布一個事件:SecondChange。觀察該類的類訂閱了該事件。
    public class Clock
    {
        // 代表小時,分鐘,秒的私有變量
        int _hour;
 
        public int Hour
        {
            get { return _hour; }
            set { _hour = value; }
        }
        private int _minute;
 
        public int Minute
        {
            get { return _minute; }
            set { _minute = value; }
        }
        private int _second;
 
        public int Second
        {
            get { return _second; }
            set { _second = value; }
        }
 
        // 要發(fā)布的事件
        public event SecondChangeHandler SecondChange;
 
        // 觸發(fā)事件的方法
        protected void OnSecondChange(
           object clock,
           TimeInfoEventArgs timeInformation
        )
        {
            // Check if there are any Subscribers
            if (SecondChange != null)
            {
                // Call the Event
                SecondChange(clock, timeInformation);
            }
        }
 
        // 讓鐘(Clock)跑起來,每隔一秒鐘觸發(fā)一次事件
        public void Run()
        {
            for (; ; )
            {
                // 讓線程Sleep一秒鐘
                Thread.Sleep(1000);
 
                // 獲取當(dāng)前時間
                System.DateTime dt = System.DateTime.Now;
 
                // 如果秒鐘變化了通知訂閱者
                if (dt.Second != _second)
                {
                    // 創(chuàng)造TimeInfoEventArgs類型對象,傳給訂閱者
                    TimeInfoEventArgs timeInformation =
                       new TimeInfoEventArgs(
                       dt.Hour, dt.Minute, dt.Second);
 
                    // 通知訂閱者
                    OnSecondChange(this, timeInformation);
                }
 
                // 更新狀態(tài)信息
                _second = dt.Second;
                _minute = dt.Minute;
                _hour = dt.Hour;
 
            }
        }
    }
 
 
    /* ======================= Event Subscribers =============================== */
 
    // 一個訂閱者。DisplayClock訂閱了clock類的事件。它的工作是顯示當(dāng)前時間。
    public class DisplayClock
    {
        // 傳入一個clock對象,訂閱其SecondChangeHandler事件
        public void Subscribe(Clock theClock)
        {
            theClock.SecondChange +=
               new SecondChangeHandler(TimeHasChanged);
        }
 
        // 實現(xiàn)了委托匹配類型的方法
        public void TimeHasChanged(
           object theClock, TimeInfoEventArgs ti)
        {
 
            Console.WriteLine("Current Time: {0}:{1}:{2}",
               ti.hour.ToString(),
               ti.minute.ToString(),
               ti.second.ToString());
        }
    }
 
    // 第二個訂閱者,他的工作是把當(dāng)前時間寫入一個文件
    public class LogClock
    {
        public void Subscribe(Clock theClock)
        {
            theClock.SecondChange +=
               new SecondChangeHandler(WriteLogEntry);
        }
 
        // 這個方法本來應(yīng)該是把信息寫入一個文件中
        // 這里我們用把信息輸出控制臺代替
        public void WriteLogEntry(
           object theClock, TimeInfoEventArgs ti)
        {
            Clock a = (Clock)theClock;
            Console.WriteLine("Logging to file: {0}:{1}:{2}",
               a.Hour.ToString(),
               a.Minute.ToString(),
               a.Second.ToString());
        }
    }
 
    /* ======================= Test Application =============================== */
 
    // 測試擁有程序
    public class Test
    {
        public static void Main()
        {
            // 創(chuàng)建clock實例
            Clock theClock = new Clock();
 
            // 創(chuàng)建一個DisplayClock實例,讓其訂閱上面創(chuàng)建的clock的事件
            DisplayClock dc = new DisplayClock();
            dc.Subscribe(theClock);
 
            // 創(chuàng)建一個LogClock實例,讓其訂閱上面創(chuàng)建的clock的事件
            LogClock lc = new LogClock();
            lc.Subscribe(theClock);
 
            // 讓鐘跑起來
            theClock.Run();
        }
    }
}


MouseEventHandler和EventHandler傳遞參數(shù)的局限性分析

    開發(fā)過程中,特別是使用自定義控件時,常常需要對一個控件的click,mouseDown,mouseUp等事件的處理進行重新定義,以滿足實際工程應(yīng)用和要求。常用的方法如下:

button1.Click -= new EventHandler(ButtonClick_Handler);
button1.MouseUp -= new MouseEventHandler(ButtonUp_Handler);
button1.Click += new EventHandler(ButtonClick_Handler);
MouseUp += new MouseEventHandler(ButtonUp_Handler);

    可以看到,這里是通過EventHandler和MouseEventHandler這兩個委托來能click和mouseup賦值。

    這兩個委托的定義如下:

EventHandler:
.NET Framework 中的事件模型基于具有事件委托,該委托將事件與事件處理程序連接。引發(fā)事件需要兩個元素:
標(biāo)識對事件提供響應(yīng)的方法的委托。
保存事件數(shù)據(jù)的類。

public delegate void EventHandler(Object sender, EventArgs e); 
public event EventHandler NoDataEventHandler;


MouseEventHandler:
表示將處理窗體、控件或其他組件的 MouseDown、MouseUp 或 MouseMove 事件的方法。
委托的原型:


public delegate void MouseEventHandler( 
    Object sender, 
    MouseEventArgs e
)

 
 這兩個委托都有兩個參數(shù),其中Sender可以通過.net的機制來捕獲,而EventArgs和MouseEventArgs 該如何使用呢?或者說如何給它賦值?暫時沒有辦法,還請高人指點。
   其實這個問題可以通過匿名委托來解決。
 
2、使用匿名委托給一些EventHandler/MouseEventHandler的方法傳參數(shù)
關(guān)鍵代碼如下:

public void setSeatButtonMove_EventHandler(CSeatButton seatBtn, Object parentForm)
{
    ///* 常規(guī)事件加載方式 */
    //seatBtn.button1.Click -= new EventHandler(seatButtonClick_Handler);
    //seatBtn.button1.MouseUp -= new MouseEventHandler(seatButtonUp_Handler);
    //seatBtn.button1.Click += new EventHandler(seatButtonClick_Handler);
    //seatBtn.button1.MouseUp += new MouseEventHandler(seatButtonUp_Handler);
    /* 匿名事件加載方式 */
    seatBtn.button1.Click -= delegate(Object o, EventArgs e) { seatButtonClick_Handler(seatBtn.button1, parentForm); };
    seatBtn.button1.MouseUp -= delegate(Object o, MouseEventArgs e) { seatButtonUp_Handler(seatBtn.button1, parentForm); };
    seatBtn.button1.Click += delegate(Object o, EventArgs e) { seatButtonClick_Handler(seatBtn.button1, parentForm); };
    seatBtn.button1.MouseUp += delegate(Object o, MouseEventArgs e) { seatButtonUp_Handler(seatBtn.button1, parentForm); };
}
public void seatButtonClick_Handler(object sender,object formOfSender)
{
    string formName = ((Form)formOfSender).Name.Trim();
    if (formName.Equals("Form1"))
    { 
        MessageBox.Show("In Form1,click a button!");
    }
    if (formName.Equals("Form2"))
    {
        MessageBox.Show("In Form2,click a button!");
    }
}


小結(jié)

(1)、在定義事件的那個類A里面,可以任意的使用事件名,可以觸發(fā);在別的類里面,事件名只能出現(xiàn)在 += 或-= 的左邊來指向函數(shù),即只能實例化,不能直接用事件名觸發(fā)。但是可以通過A類的對象來調(diào)用A類中的觸發(fā)事件的函數(shù)。這是唯一觸發(fā)事件的方式。

(2)、不管是多播委托還是單播委托,在沒有特殊處理的情況下,在一個線程的執(zhí)行過程中去調(diào)用委托(委托對象所指向的函數(shù)),調(diào)用委托的執(zhí)行是不會新起線程的,這個執(zhí)行還是在原線程中的,這個對于事件也是一樣的。當(dāng)然,如果是在委托所指向的函數(shù)里面去啟動一個新的線程那就是另外一回事了。

(3)、事件是針對某一個具體的對象的,一般在該對象的所屬類A中寫好事件,并且寫好觸發(fā)事件的方法,那么這個類A就是事件的發(fā)布者,然后在別的類B里面定義A的對象,并去初始化該對象的事件,讓事件指向B類中的某一個具體的方法,B類就是A類事件的訂閱者。當(dāng)通過A類的對象來觸發(fā)A類的事件的時候(只能A類的對象來觸發(fā)A類的事件,別的類的對象不能觸發(fā)A類的事件,只能訂閱A類的事件,即實例化A類的事件),作為訂閱者的B類會接收A類觸發(fā)的事件,從而使得訂閱函數(shù)被執(zhí)行。一個發(fā)布者可以有多個訂閱者,當(dāng)發(fā)布者發(fā)送事件的時候,所有的訂閱者都將接收到事件,從而執(zhí)行訂閱函數(shù),但是即使是有多個訂閱者也是單線程。




如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答??! 點擊進入論壇

發(fā)表評論 (4678人查看,0條評論)
請自覺遵守互聯(lián)網(wǎng)相關(guān)的政策法規(guī),嚴(yán)禁發(fā)布色情、暴力、反動的言論。
昵稱:
最新評論
------分隔線----------------------------

其它欄目

· 建站教程
· 365學(xué)習(xí)

業(yè)務(wù)咨詢

· 技術(shù)支持
· 服務(wù)時間:9:00-18:00
365建站網(wǎng)二維碼

Powered by 365建站網(wǎng) RSS地圖 HTML地圖

copyright © 2013-2024 版權(quán)所有 鄂ICP備17013400號