Trong các ứng dụng Windows Form, khi ta click một button hay click chọn
một mục trong listbox, thì đều phát sinh một sự kiện (event). Chương
trình có nhiệm vụ xử lý các sự kiện này. Chính cơ chế này đã tạo ra khả
năng tương tác linh hoạt giữa người dùng và chương trình. Người dùng gửi
đến chương trình các yêu cầu thông qua các sự kiện, chương trình đáp
ứng sự kiện đó và thực hiện một tác vụ nào đó.
Những sự kiện đó đều được thực thi bởi cơ chế ủy quyền (delegate). Trong
bài viết này, tôi sẽ giới thiệu với các bạn khái niệm delegate và cách
sử dụng nó để tạo sự kiện trong C#.
Delegate là gì ?
Delegate đơn giản chỉ là một kiểu dữ liệu tham chiếu (reference type)
dùng để đóng gói một phương thức với tham số và kiểu trả về xác định.
Chúng ta có thể đóng gói bất kỳ phương thức nào trong một delegate thích
hợp.
Delegate trong C# cũng tương tự như con trỏ hàm trong C++ (function
pointer). Bạn sẽ hiểu rất nhanh về delegate nếu bạn đã từng sử dụng con
trỏ hàm trong C++.
Delegate thường được sử dụng để tạo các sự kiện và các hàm callback cho chương trình.
Khai báo delegate
Để tạo delegate, bạn sử dụng từ khóa delegate theo cú pháp sau :
[access modifier] delegate [return type] <name> (<arguments>);
Trong đó :
- access modifier : là một trong các thuộc tính truy cập : private, public, protected, internal.
- return type : kiểu trả về của phương thức
- name : tên của delegate
- arguments : các tham số của phương thức
* Chú ý : delegate chỉ mô tả dạng tổng quát của phương thức, bao gồm
kiểu trả về và tham số. Còn phương thức cụ thể sẽ được truyền vào thông
qua một thể hiện (instance) của delegate. VD :
PHP Code:
public delegate void delSay(string Message);
Delegate này có thể đóng gói bất kỳ phương thức nào nhận vào một chuỗi và không trả về kết quả.
Sử dụng delegate
Để sử dụng delegate, bạn phải tạo một thể hiện cho nó và truyền một
phương thức phù hợp (về kiểu trả về và tham số) vào hàm khởi tạo của nó.
VD :
PHP Code:
namespace DelegateAndEventDemo
{
public delegate void delSay(string Msg);
class Program
{
static void Main(string[] args)
{
delSay speaker = new delSay(Speak);
speaker("Hello");
Console.ReadLine();
} private static void Speak(string Msg)
{
Console.WriteLine(Msg);
}
}
}
Trong ví dụ trên, tôi đã tạo một delegate tên delSay, có thể đóng
gói một phương thức có kiểu trả về là void và một tham số kiểu string.
Sau đó, tôi tạo một thể hiện của delSay, truyền vào phương thức khởi tạo
của nó hàm Speak. Hàm này có dạng giống hệt dạng đã khai báo của
delegate delSay. Khi tôi gọi delSay và truyền cho nó chuỗi "Hello", nó
sẽ gọi hàm Speak và truyền chuỗi "Hello" cho hàm này.
Như vậy, bằng cách trên, chúng ta đã "gắn" hàm Speak vào delegate delSay.
Kỹ thuật Multicast
C# cho phép chúng ta "gắn" nhiều phương thức vào cùng một delegate, miễn
là các phương thức này có cùng kiểu trả về và tham số với delegate. Và
khi ta gọi delegate này, tất cả các phương thức đã được "gắn" sẽ thi
hành cùng lúc. Kỹ thuật này gọi là "Multicast".
Chú ý : một Multicast delegate chỉ chấp nhận phương thức có kiểu trả về là void.
Để thực hiện Multicast, ta tạo các thể hiện của một multicast
delegate, gắn nó với các phương thức tương ứng. Sau đó dùng toán tử "+"
để gom các delegate này vào thành 1 delegate duy nhất. Dưới đây là ví
dụ minh họa :
PHP Code:
namespace DelegateAndEventDemo
{
public delegate void DoAction(string Msg);
class Program
{
static void Main(string[] args)
{
//Tạo 2 delegate riêng lẻ
DoAction speaker = new DoAction(Speak);
DoAction writer = new DoAction(Write);
//Thực hiện multi cast, ghép nhiều delegate lại với nhau
DoAction multicast = speaker + writer;
//Gọi delegate
multicast("Hello");
Console.ReadLine();
}
private static void Speak(string Msg)
{
Console.WriteLine("Speak : {0}",Msg);
}
private static void Write(string Msg)
{
Console.WriteLine("Write : {0}", Msg);
}
}
}
Như ví dụ trên : đầu tiên ta tạo 2 delegate speaker và writer gắn
2 hàm Speak và Write vào. Sau đó tạo delegate tên là multicast và
"cộng" 2 delegate speaker, writer lại với nhau. Như vậy khi gọi delegate
multicast, hai delegate speaker và writer sẽ đồng thời được gọi.
Ngoài toán tử "+", C# còn hỗ trợ toán tử "+=" và "-=" trên delegate. VD :
PHP Code:
multicast += speaker;
multicast -= writer;
Sự kiện (Event)
Một trong những ứng dụng thường thấy nhất của delegate là sự kiện. Mỗi sự kiện thực chất là một delegate.
Bạn tạo một project mới kiểu Windows Form, vẽ lên Form một button tên là
button1. Sau đó, bạn double click vào button, Visual Studio sẽ sinh cho
bạn các đoạn mã sau :
Trong tập tin
Form1.cs :
PHP Code:
...
private void button1_Click(object sender, EventArgs e)
{
}
...
Trong tập tin
Form1.Designer.cs :
PHP Code:
...
#region Windows Form Designer generated code
...
this.button1.Click += new System.EventHandler(this.button1_Click);
...
#endregion
...
Như bạn thấy, khi bạn cài đặt sự kiện Click cho button, một thể
hiện của delegate System.EventHandler được tạo ra và gắn với phương thức
button1_Click. Sau đó delegate này được gắn vào sự kiện của lớp Button.
Để cài đặt một sự kiện cho một lớp như trên. Bạn phải tạo một delegate và một event tương ứng. Cách khai báo như sau :
[access modifier] event [delegate type] <name>;
Trong đó :
- access modifier : là thuộc tính truy cập (private, public, protected, internal)
- delegate type : kiểu delegate cần sử dụng
- name : tên của sự kiện
VD :
PHP Code:
public delegate void OnCreatingHandler();
public event OnCreatingHandler OnCreating;
Chú ý : để tránh trùng tên và dễ phân biệt, ta nên thêm chữ "On"
vào tên của event và delegate, đồng thời thêm "Handler" vào sau tên của
delegate để cho biết đây là delegate dùng cho sự kiện.
Sau đó bạn có thể phát sự kiện ở bất cứ đâu trong lớp bằng cách gọi tên sự kiện và truyền vào tham số tương ứng.
Cuối cùng, bạn phải gắn sự kiện này với một hoặc nhiều phương thức để xử lý sự kiện.
VD đầy đủ :
PHP Code:
using System;
namespace EventDemo
{
class MyClass
{
public delegate void OnCreatingHandler(int Args); //khai báo delegate
public event OnCreatingHandler OnCreating; //khai báo sự kiện
public MyClass()
{
}
public void DoWork()
{
int Number = 10; //tham số cần truyền
OnCreating(Number); //phát sinh sự kiện
}
}
class Program
{
static void Main(string[] args)
{
MyClass M = new MyClass();
//gắn hàm xử lý vào sự kiện
M.OnCreating += new MyClass.OnCreatingHandler(M_OnCreating);
//sự kiện sẽ phát sinh khi gọi phương thức này
M.DoWork();
Console.ReadLine();
}
//hàm xử lý sự kiện
static void M_OnCreating(int Args)
{
Console.WriteLine("Tham so nhan duoc : {0}", Args);
}
}
}
Như vậy, chúng ta đã tìm hiểu xong về delegate và sự kiện trong
C#. Ngoài những ứng dụng trên, bạn có thể tìm thấy một ứng dụng khác của
delegate
tại đây.