C 中動態訂閱控制項中任意事件的方法

2022-01-20 18:00:09 字數 3169 閱讀 1929

這個題目想了半天,不太好用一句話描述。這樣,舉個簡單的應用場景:在用windows forms製作嚮導程式的時候,通常會有「上一步」、「下一步」這樣的按鈕。假設現在需要做乙個通用的「嚮導製作框架」,那麼我們就需要在這個「嚮導製作框架」中,對「上一步」、「下一步」這些按鈕是否可用(是否enabled)進行控制。而控制條件是由開發人員在實際使用「嚮導製作框架」進行開發時確定的。比如:只有在當前嚮導頁面的某個文字框裡被輸入了字串以後,「下一步」才可用;或者只有在某個按鈕被按下的時候,「下一步」才可用。於是,我們的「嚮導製作框架」要能夠允許開發人員來確定,當觸發什麼事情的時候,「下一步」才可用。

我們先從特例入手,假設嚮導頁面上只有乙個按鈕叫btn,只有點選btn以後,「下一步」才能夠被點選。程式設計上很容易實現這個效果:直接在窗體上訂閱btn的click事件,在click事件裡,寫下「btnnext.enabled = true;"這樣一句話。

現在問題來了:我們需要為開發人員提供乙個「嚮導製作框架」,也就是說,這個框架根本無法**開發人員需要訂閱哪些控制項的哪些事件,只能留出乙個介面,讓開發人員自己呼叫這個介面實現事件的動態註冊。windows forms提供的控制項型別多種多樣,而且不同的事件有著不同的函式簽名(也就是委託,比如click事件和mousedown事件就是用的兩個不同的委託),如何讓我們的框架能夠支援任意的控制項,並在任意控制項的任意事件發生時,呼叫「btnnext.enabled = true;」這條語句,使得「下一步」按鈕可用呢?

要實現這樣的功能,我們需要用到反射。首先,定義乙個泛型方法,在這個方法裡,我們直接對btnnext進行設定,如下:

protected void dotrigger(object sender, t eventargs)

where t : system.eventargs

然後,根據使用者給定的控制項例項和事件名稱,獲得eventinfo物件。這個eventinfo裡有個重要的屬性,就是eventhandlertype,它就是定義event所使用的委託型別。為了使開發人員指定的事件能夠繫結到上面的dotrigger函式上,我們需要知道那個eventargs的具體型別,下面的**可以將某個委託型別的所有引數型別全部讀取出來:

private type getdelegateparametertypes(type d)

methodinfo invoke = d.getmethod("invoke");

if (invoke == null)

parameterinfo parameters = invoke.getparameters();

type typeparameters = new type[parameters.length];

for (int i = 0; i < parameters.length; i++)

return typeparameters;

}

注意:如果是標準的事件委託,一般情況下都是第乙個引數為object型別,第二個引數為eventargs繫結型別,無返回值的簽名格式。換句話說,一般情況下,上面的這段**返回的陣列包含兩個物件:object和乙個繼承於eventargs(或者是eventargs本身)的型別。在這裡,我們取陣列裡的第二個成員。

好了,現在通過反射,獲得dotrigger方法的methodinfo,並通過methodinfo.makegenericmethod方法,將上一步獲得的eventargs型別繫結到dotrigger方法上,並使用delegate.createdelegate生成event handler:

private delegate geteventhandler(control control, eventinfo eventinfo)

' on the control ''.",

eventinfo.name, control));

type delegateparameters = this.getdelegateparametertypes(eventinfo.eventhandlertype);

if (delegateparameters == null ||

delegateparameters.length != 2)

throw new invalidoperationexception(string.format("event '' is not valid.", eventinfo.name));

type eventargstype = delegateparameters[1];

methodinfo doeventmethod = this.gettype().getmethod("dotrigger",

bindingflags.nonpublic | bindingflags.instance);

if (doeventmethod == null)

throw new exception("dotrigger method doesn't exist.");

if (!doeventmethod.isgenericmethod)

throw new exception("dotrigger method is not a generic method.");

methodinfo concretedoeventmethod = doeventmethod.makegenericmethod(eventargstype);

delegate d = delegate.createdelegate(eventinfo.eventhandlertype, this, concretedoeventmethod);

return d;

}catch

}

通過向上面的方法傳入乙個任意控制項和該控制項中任意事件的method info,即可獲得處理該事件的event handler,也就是由dotrigger泛型方法來處理該指定的事件:

public void registertrigger(control control, string eventname)

catch

}

最後,在使用的時候,**就簡單啦:

private void form_load (object sender, system.eventargs e)

現在,不管是btn被單擊,還是textbox1裡的文字被更改,還是在textbox2滑鼠按鈕被按下,都會直接觸發dotrigger函式,進而使得「下一步」按鈕變得可用(enabled為true)。

C 中刪除任意控制項任意事件的事件列表的實現!

有時候遇到動態掛接事件的時候,可能想刪除以前掛接的事件。因為如果不刪除,事件是會重複掛接的。這裡給出兩種實現方法,各有優缺點。1。利用反射機制實現 void clearevent control control,string eventname 很簡單,就兩行 但是以後自己新增事件就用這個方法,以便...

C 中動態建立控制項及事件處理程式

using system using system.drawing using system.collections using system.componentmodel using system.windows.forms using system.data namespace miner cl...

C 事件的傳送方和接收方(訂閱方)

基於windows的應用程式也是基於訊息的,windows使用預定義訊息與應用程式通訊。net framework將windows訊息封裝在事件中,可以把事件作為物件之間的通訊介質。事件傳送方 傳送事件的物件 事件接收方 捕獲事件並對其作出響應的物件 處理事件 在事件通訊機制中,事件傳送方不知道哪個...