Nội dung bài viết
Đăng ký học lập trình C++
Tại STDIO bạn được dạy nền tảng lập trình tốt nhất.
Đăng ký học
Nguyễn Nghĩa Thông thường khi mới bắt đầu lập trình giao diện Windows From Application, Windows Phone, chúng ta thường xuyên tiếp xúc với những sự kiện như Click của Button, TextChanged của Textblock. Vậy những sự kiện đó được xây dựng như thế này thì trong bài viết này sẽ làm rõ cũng như cách viết ra những sự kiện như vậy để giúp bạn đọc có thể hiểu rõ sâu hơn về sự kiện trong C#.

Giới thiệu

Thông thường khi mới bắt đầu lập trình giao diện Windows From Application, Windows Phone, chúng ta thường xuyên tiếp xúc với những sự kiện như Click của Button, TextChanged của Textblock. Những phương thức xử lý sự kiện tương ứng như:

void btnSubmit_Clicked(object sender, System.EventArgs e)

void txtContent_TextChanged(object sender, RoutedEventArgs e)

Vậy những sự kiện đó được xây dựng như thế nào, những đối số sender, e  ở hai phương thức trên có ý nghĩa như thế nào thì trong bài viết này sẽ làm rõ cũng như cách viết ra những sự kiện như vậy để giúp bạn đọc có thể hiểu rõ sâu hơn về sự kiện trong C#.

Tiền đề bài viết

Lúc mới bắt đầu lập trình C#, tôi nhận thấy không phải ai cũng có thể hiểu được khái niệm event, cũng như cách tạo ra nó như thế nào. Sau một quá trình học tìm hiểu, học tập tôi muốn chia sẽ kiến thức khá bổ ích này cùng các độc giả.

Đối tượng hướng đến

Những lập trình viên C#, gặp khó khăn khi tiếp cận với khái niệm event trong ngôn ngữ lập trình C#.

Các bạn nên xem qua bài viết Delegates và Events trong C# của tác giả Hiếu Nguyễn để có tiếp cận bài viết này một cách dễ dàng.

Khai báo sự kiện

Trong bài viết này tôi sẽ lấy ví dụ là 1 sản phẩm (Product) có trường dữ liệu là giá của sản phẩm (Price). Khi mà trường dữ liệu này thay đổi thì sẽ phát sinh sự kiện và có các thông tin gửi kèm theo sự kiện là giá cũ và giá mới (OldPrice) và giá mới (NewPrice).

Để khai báo một sự kiện trước tiên ta tạo một delegate.

void delegate PriceChangedHandler(decimal oldPrice, decimal newPrice)

Khai báo sự kiện

public  delegate void PriceChangedHandler(decimal oldPrice, decimal newPrice);
public class Product
{
   public event PriceChangedHandler PriceChanged;  
}

Triển khai sự kiện

Phần trên chúng ta đã khai báo sự kiện PriceChanged. Bây giờ ta sẽ đi tiếp phần tiếp theo là triển khai sự kiện này để khi giá (Price) thay đổi thì sẽ phát sinh sự kiện;

Khai báo trường dữ liệu của class Product:

private decimal _price;

và triển khai sự kiện sử dụng get set

public class Product
{
    private decimal _price;
    public event PriceChangedHandler PriceChanged;  
    public decimal Price
    {
        get
        {
            return this._price;
        }
        set
        {
            if (_price == value)
                return;
            decimal oldPrice = _price;
            _price = value;
            if (PriceChanged != null)
                PriceChanged(oldPrice, _price);
        }
    }     
}

Triển khai hàm Main:

class Program
    {
        static void Main(string[] args)
        {
            Product product = new Product();
            product.Price = 10000;
            product.PriceChanged += product_PriceChanged;
            product.Price = 50000;
            Console.ReadLine();
        }

        static void product_PriceChanged(decimal oldPrice, decimal newPrice)
        {
            Console.WriteLine("Old Price: {0}", oldPrice);
            Console.WriteLine("New Price: {0}", newPrice);
        }
    }

Trong mô hình sự kiện có hai khai niệm các bạn cần quan tâm là đối tượng phát sinh sự kiện (Broadcaster), và phương thức xử lý sự kiện (Subscriber).

  • Broadcaster: Là kiểu chứa event, ở trên là Product. Hoặc có thể là Button, Textblock, Combobox.
  • Subscriber: Là phương thức đăng kí và xử lý sự kiện do những đối tượng ở Broadcaster phát sinh.

Mô hình chuẩn sự kiện trong .Net

Nhiều khi chúng ta cần phải tạo ra nhiều sự kiện, mỗi sự kiện có cách viết khác nhau, không đồng bộ. Để khắc phục nhược điểm đó thì .Net Framework có đưa là một mô hình chuẩn để viết sự kiện giúp cho việc viết sự kiện dễ dàng. Mô hình này như sau:

Khai báo delegate có quy tắc rằng buộc:

  • Delegate có kiểu trả về là kiểu void.
  • Delegate có hai tham số, tham số thứ nhất có kiểu là object, tham số thứ hai có kiểu EventArgs. object chính là đối tượng phát sinh sự kiện, EventArgs chính là class giữ thông tin mà đối tượng gửi kèm trong quá trình phát sinh sự kiện.

Class PriceChangedEventArgs:

public class PriceChangedEventArgs
{
	public readonly decimal OldPrice;
	public readonly decimal NewPrice;
	
	public PriceChangedEventArgs(decimal oldPrice, decimal newPrice)
	{
		this.OldPrice = oldPrice;
		this.NewPrice = newPrice;
	}
}

Khai báo delegate

public delegate void PriceChangedHandler(object sender, PriceChangedEventArgs e);

Cuối cùng là tạo một phương thức virtual có phạm vi truy xuất là protect có nhiệm vụ phát sinh sự kiện:

protected virtual void OnPriceChanged(PriceChangedEventArgs e)
{
	if (PriceChanged != null)
		PriceChanged(this, e);
}

Triển khai sự kiện sử dụng get set

public decimal Price
{
	get
	{
		return this._price;
	}
	set
	{
		if (_price == value)
			return;
		decimal oldPrice = _price;
		_price = value;
		OnPriceChanged(new PriceChangedEventArgs(oldPrice, _price));
	}
}

Triển khai hàm main

class Program
{
	static void Main(string[] args)
	{
		Product product = new Product();
		product.Price = 10000;
		product.PriceChanged += product_PriceChanged;
		product.Price = 50000;
		Console.ReadLine();
	}

	static void product_PriceChanged(object sender, PriceChangedEventArgs e)
	{
		Console.WriteLine("Old Price: {0}", e.OldPrice);
		Console.WriteLine("New Price: {0}", e.NewPrice);
	}
}

Các bạn để ý thấy phương thức xử lý sự kiện ở đây

void product_PriceChanged(object sender, PriceChangedEventArgs e)

Có điểm tương đồng với phương thức xử lý sự kiện click của Button hay TextChanged của TextBlock. Đến đây thì các bạn có thể hiểu được các tham số trong những phương thức này có ý nghĩa như thế nào.

Ngoài ra chúng ta có thể ép kiểu sender về Product

static void product_PriceChanged(object sender, PriceChangedEventArgs e)
{
	Product p = sender as Product;
	Console.WriteLine("Price: {0}", p.Price);
	Console.WriteLine("Old Price: {0}", e.OldPrice);
	Console.WriteLine("New Price: {0}", e.NewPrice);
}

Lưu ý

Với những quy tắc đặt ra như vậy, việc tuân thủ hay không là tùy theo mỗi lập trình viên, ví dụ tôi nhận thấy class Product của tôi không cần thiết phải viết thêm phương thức OnPriceChanged mà tôi có thể triển khai trực tiếp như sau:

public decimal Price
{
	get
	{
		return this._price;
	}
	set
	{
		if (_price == value)
			return;
		decimal oldPrice = _price;
		_price = value;
		if (PriceChanged != null)
			PriceChanged(this, new PriceChangedEventArgs(oldPrice, _price));
	}
}

Download demo

Demo_Event_VS2013.zip

THẢO LUẬN
ĐÓNG