DEV Community

mohamed Tayel
mohamed Tayel

Posted on

C# Advanced: Passing Data into Event Handlers

Meta Description:

Learn how to pass data into event handlers in C#. This article explains how to use custom event data in a stock management system, with assignments at three levels of difficulty.


Introduction

In C#, event handlers often need to pass data to subscribers so that they can act based on the event context. The EventHandler delegate allows you to pass data using EventArgs. You can extend EventArgs to create custom data for your events, making event-driven communication more efficient and informative.

In this article, we’ll explore how to pass data into event handlers using a stock management system example. We’ll cover the creation of custom event data classes and demonstrate how event subscribers can handle and utilize this data. Finally, we’ll provide assignments to help you apply these concepts at different levels of difficulty.


1. The Importance of Passing Data into Event Handlers

When an event occurs, the event handler often needs to know details about what happened. For example, in our stock management system, when stock levels fall below a certain threshold, we may want to pass the current stock level and the product’s details to the event subscribers. This data can be useful for actions such as notifying a supplier or adjusting inventory.

In C#, event data is typically passed using the EventArgs class or its generic equivalent, EventHandler<T>. You can extend EventArgs to include the specific data your event needs to communicate.


2. Stock Management System Example with Custom Event Data

Let’s enhance our stock management system by passing more detailed data to event subscribers. We’ll create a custom event data class, StockChangedEventArgs, which will include both the old and new stock levels. This allows the event subscribers, such as the WarehouseManager, to react more effectively to changes in stock levels.

Step 1: Create a Custom EventArgs Class

First, we’ll create the StockChangedEventArgs class, which inherits from EventArgs and holds the stock details.

using System;

public class StockChangedEventArgs : EventArgs
{
    public string ItemName { get; set; }
    public int OldStock { get; set; }
    public int NewStock { get; set; }

    public StockChangedEventArgs(string itemName, int oldStock, int newStock)
    {
        ItemName = itemName;
        OldStock = oldStock;
        NewStock = newStock;
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Modify the InventoryManager to Use the Custom EventArgs

Next, we modify the InventoryManager to use StockChangedEventArgs when raising the StockLow event. We’ll pass the old and new stock levels to subscribers.

public class InventoryManager
{
    public event EventHandler<StockChangedEventArgs> StockLow;

    private int _stockLevel;
    public string ItemName { get; set; }

    public InventoryManager(string itemName, int initialStock)
    {
        ItemName = itemName;
        _stockLevel = initialStock;
    }

    public void ProcessSale(int quantity)
    {
        int oldStock = _stockLevel;
        _stockLevel -= quantity;
        Console.WriteLine($"{quantity} {ItemName}(s) sold. Current stock: {_stockLevel}");

        if (_stockLevel < 5)
        {
            OnStockLow(oldStock, _stockLevel);
        }
    }

    protected virtual void OnStockLow(int oldStock, int newStock)
    {
        StockLow?.Invoke(this, new StockChangedEventArgs(ItemName, oldStock, newStock));
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Update Subscribers to Handle the Custom Event Data

Now we’ll modify the WarehouseManager to handle the new event data, reacting to the old and new stock levels passed through StockChangedEventArgs.

public class WarehouseManager
{
    public void Restock(object sender, StockChangedEventArgs e)
    {
        Console.WriteLine($"Warehouse notified: Restock {e.ItemName}. Stock changed from {e.OldStock} to {e.NewStock}.");
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Run the Program

Finally, we’ll simulate the stock change and trigger the event.

public class Program
{
    public static void Main(string[] args)
    {
        InventoryManager inventory = new InventoryManager("Laptop", 10);
        WarehouseManager warehouse = new WarehouseManager();

        // Subscribe to the StockLow event
        inventory.StockLow += warehouse.Restock;

        // Simulate sales that reduce stock and trigger the event
        inventory.ProcessSale(3);  // Stock = 7, no event
        inventory.ProcessSale(4);  // Stock = 3, event triggered
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • The InventoryManager tracks stock levels and raises the StockLow event when stock falls below 5.
  • The StockChangedEventArgs class holds information about the old and new stock levels.
  • The WarehouseManager responds to the event by processing the stock change and printing a message with the old and new stock values.

3. Why Use Custom Event Data?

Using custom event data allows you to pass meaningful information to subscribers, making event-driven systems more powerful and flexible. In our stock management system, the WarehouseManager can take different actions based on both the old and new stock levels. This additional context improves the ability to react appropriately to changes.


Full Code: Stock Management System with Custom Event Data

using System;

public class StockChangedEventArgs : EventArgs
{
    public string ItemName { get; set; }
    public int OldStock { get; set; }
    public int NewStock { get; set; }

    public StockChangedEventArgs(string itemName, int oldStock, int newStock)
    {
        ItemName = itemName;
        OldStock = oldStock;
        NewStock = newStock;
    }
}

public class InventoryManager
{
    public event EventHandler<StockChangedEventArgs> StockLow;

    private int _stockLevel;
    public string ItemName { get; set; }

    public InventoryManager(string itemName, int initialStock)
    {
        ItemName = itemName;
        _stockLevel = initialStock;
    }

    public void ProcessSale(int quantity)
    {
        int oldStock = _stockLevel;
        _stockLevel -= quantity;
        Console.WriteLine($"{quantity} {ItemName}(s) sold. Current stock: {_stockLevel}");

        if (_stockLevel < 5)
        {
            OnStockLow(oldStock, _stockLevel);
        }
    }

    protected virtual void OnStockLow(int oldStock, int newStock)
    {
        StockLow?.Invoke(this, new StockChangedEventArgs(ItemName, oldStock, newStock));
    }
}

public class WarehouseManager
{
    public void Restock(object sender, StockChangedEventArgs e)
    {
        Console.WriteLine($"Warehouse notified: Restock {e.ItemName}. Stock changed from {e.OldStock} to {e.NewStock}.");
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        InventoryManager inventory = new InventoryManager("Laptop", 10);
        WarehouseManager warehouse = new WarehouseManager();

        // Subscribe to the StockLow event
        inventory.StockLow += warehouse.Restock;

        // Simulate sales that reduce stock and trigger the event
        inventory.ProcessSale(3);  // Stock = 7, no event
        inventory.ProcessSale(4);  // Stock = 3, event triggered
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Assignments to Practice Passing Data into Event Handlers

Here are three assignments to help you practice passing data into event handlers:

Easy Level:

Modify the StockChangedEventArgs class to include the name of the person who processed the sale. Pass this information along with the old and new stock levels to the event subscribers.

Hint: Add a new property to StockChangedEventArgs and pass the value when raising the event.

Medium Level:

Extend the program to handle multiple products. Create a dictionary in the InventoryManager to track multiple items, each with its own stock level. Modify the event to include the product’s unique identifier along with the stock levels.

Hint: Use a Dictionary<string, int> to track products and stock levels. Update the event data accordingly.

Difficult Level:

Make the event asynchronous. Modify the WarehouseManager to handle the StockLow event asynchronously. Use Task.Run to simulate time-consuming operations in the event handler, such as reordering stock.

Hint: Use async and await in the event handler, and ensure that the event handling works correctly in an asynchronous environment.


Conclusion

Passing custom data into event handlers is a key technique in making event-driven systems more flexible and powerful. By using custom event arguments, you can give subscribers the context they need to make informed decisions. In this article, we’ve shown how to pass stock information in a stock management system and provided practical assignments to deepen your understanding of the topic.

Top comments (0)