C#委託和事件(WPF實現關閉子視窗B時觸發A視窗事件)
遇到一個問題,子視窗關閉時,主視窗如何知道子視窗關閉了,並執行相應的處理事件。為了解決這個問題查閱資料後可以用委託和事件來完成。
一、委託
1、委託:
委託是安全封裝方法的型別,類似於 C 和 C++ 中的函式指標。 與 C 函式指標不同的是,委託是面向物件的、型別安全的和可靠的。假如委託沒有引用一個有效的方法,就不允許呼叫這個委託。
委託是指向一個方法的指標,而且我們採用和呼叫方法一樣的方式呼叫它。呼叫一個位委託時,執行時實際執行的是委託所引用的方法。可以動態的更改一個委託引用的方法,使呼叫一個委託的程式碼每次都執行一個不同的方法。
委託(Delegate)特別用於實現事件和回撥方法。所有的委託(Delegate)都派生自 System.Delegate 類。
委託用於將方法作為引數傳遞給其他方法。 事件處理程式就是通過委託呼叫的方法。 你可以建立一個自定義方法,當發生特定事件時,某個類(如 Windows 控制元件)就可以呼叫你的方法。
委託具有以下屬性:
-
委託類似於 C++ 函式指標,但它們是型別安全的。
-
委託允許將方法作為引數進行傳遞。
-
委託可用於定義回撥方法。
-
委託可以連結在一起;例如,可以對一個事件呼叫多個方法。
2、使用委託的步驟
第一步:定義委託
與類一樣,委託型別必須在被用來建立變數以及型別物件之前宣告。
委託的宣告原型是
delegate <函式返回型別> <委託名> (<函式引數>)
public delegate void MyDelegate ( );
第二步:委託的例項化,並將這個例項引用一個相匹配的方法
方法1:使用new關鍵字
<委託型別> <例項化名>=new <委託型別>(<註冊函式>)
MyDelegate myIN = new MyDelegate(WriteToScreen);//例項化委託
pubic void WriteToScreen()
{
}
方法2:使用 += 號將例項引用一個相匹配的方法。
class Myclass
{
public delegate void MyDelegate ();
MyDelegate void myIN;//建立一個委託的例項
public Myclass()
{
this.myIN +=run;
}
Private void run()
{
}
}
第三步:呼叫委託
完整步驟舉例:
4、委託的作用
委託時一種在C#中實現函式動態呼叫的方式,通過委託可以將一些相同型別的函式串聯起來依次執行。委託同時還是函式回撥和事件機制的基礎。
例項化委託是將委託指向或引用某個方法,也就是必須要將某一個方法作為引數傳遞委託的構造方法。
二、事件
1、 事件(Event) 基本上說是一個使用者操作,如按鍵、點選、滑鼠移動等等,或者是一些出現,如系統生成的通知。應用程式需要在事件發生時響應事件。例如,中斷。事件是用於程序間通訊。
.NET中的事件,我們可以定義並捕捉特定的事件,並安排呼叫委託來處理髮生的事件。
2、事件在類中宣告且生成,且通過使用同一個類或其他類中的委託與事件處理程式關聯。包含事件的類用於釋出事件。這被稱為 釋出器(publisher) 類。其他接受該事件的類被稱為 訂閱器(subscriber) 類。事件使用 釋出-訂閱(publisher-subscriber) 模型。
釋出器(publisher) 是一個包含事件和委託定義的物件。事件和委託之間的聯絡也定義在這個物件中。釋出器(publisher)類的物件呼叫這個事件,並通知其他的物件。
訂閱器(subscriber) 是一個接受事件並提供事件處理程式的物件。在釋出器(publisher)類中的委託呼叫訂閱器(subscriber)類中的方法(事件處理程式)。
3、宣告事件
由於事件的設計隨同委託使用的,所以事件的型別必須是一個委託,而且在宣告前附加event關鍵字作為字首。
(1)在類的內部宣告事件,首先必須宣告該事件的委託型別。
如:
public delegate void BoilerLogHandler( );
(2)然後,宣告事件本身,使用 event 關鍵字:
// 基於上面的委託定義事件
public event BoilerLogHandler BoilerEventLog;
定義了一個名為 BoilerLogHandler 的委託和一個名為 BoilerEventLog 的事件,該事件在生成的時候會呼叫委託。
4、 釋出-訂閱(publisher-subscriber) 模型
(1)訂閱事件:把方法新增到一個事件中。
釋出器:看做是一個期刊社
訂閱器:看做一個讀者
首先,讀者訂閱期刊社的一個期刊。相當於註冊事件
然後,當期刊要發行時,會通過電話、郵件等方式通知讀者。相當於觸發事件
最後,當讀者收到這個通知時候,會選擇買期刊或者不買等一系列行為。相當於響應事件
舉例: https://www.cnblogs.com/yinqixin/p/5056307.html
三、委託和事件應用舉例
using System;
namespace SimpleEvent
{
using System;
/***********釋出器類***********/
public class EventTest
{
private int value;
public delegate void NumManipulationHandler();//宣告委託
public event NumManipulationHandler ChangeNum;//宣告事件
protected virtual void OnNumChanged()
{
if ( ChangeNum != null )
{
ChangeNum(); /* 第三步事件被觸發,執行事件處理方法*/
}
else
{
Console.WriteLine( "event not fire" );
Console.ReadKey(); /* 回車繼續 */
}
}
public EventTest() //構造方法
{
int n = 5;
SetValue( n );
}
public void SetValue( int n )
{
if ( value != n )
{
value = n;
OnNumChanged();
}
}
}
/***********訂閱器類***********/
public class subscribEvent
{
public void printf()
{
Console.WriteLine( "event fire" );
Console.ReadKey(); /* 回車繼續 */
}
}
/***********觸發***********/
public class MainClass
{
public static void Main()
{
EventTest e = new EventTest(); /* 例項化物件,第一次沒有觸發事件 */
subscribEvent v = new subscribEvent(); /* 例項化物件 */
e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* 第一步註冊事件 */
e.SetValue( 7 );//第二步觸發事件,事件生成時呼叫委託
e.SetValue( 11 );//第二步觸發事件,事件生成時呼叫委託
}
}
}
當上面的程式碼被編譯和執行時,它會產生下列結果:
event not fire
event fire
event fire
另外一個例子:C#事件的訂閱與觸發
四、WPF實現關閉子視窗B時觸發A視窗事件
最後總結簡單的委託事件的應用只需要五步法。
1、定義子視窗B
釋出器功能:
//第一步,定義委託,委拖不屬於任何一個類
public delegate void ChangeTextHandler();
public partial class B : Window //事件釋出類
{
//第二步,宣告事件
public event ChangeTextHandler ChangeTextEvent;
public B()
{
InitializeComponent();
}
//點選子視窗B上的一個按鈕觸發事件
private void btnCalibraEnter_Click(object sender, RoutedEventArgs e)
{
this.Close();//關閉視窗B
//第四步,呼叫事件
ChangeTextEvent();
}
}
2、定義視窗A,通過視窗A開啟子視窗B,開啟子視窗B後立即關閉視窗A
訂閱器功能:
public partial class A : Window
{
public A()
{
InitializeComponent();
}
//點選視窗A上的按鈕,關閉視窗A,並註冊事件
private void btnNext_Click(object sender, RoutedEventArgs e)
{
this.Close();//關閉當前視窗
//例化視窗B
B demaWin = new B();
demaWin.ChangeTextEvent += new ChangeTextHandler(method);//第三步,註冊事件
demaWin.Show();//開啟視窗B
}
//第五步,事件發生時要呼叫的方法
private void method()
{
//雖然當前視窗A已經關閉,但是事件觸發時,程式依然可以執行到這裡
}
}