Sunday 1 September 2013

C# Delegates Series Part 3 - Delegates can be used to define event handlers and provide event handling mechanism

Below is the reference of all posts in this series

  1. C# Delegates Series Part 1 - Overview
  2. C# Delegates Series Part 2 - Delegates allows methods to be passed as parameters
  3. C# Delegates Series Part 3 - Delegates can be used to define event handlers and event handling mechanism
  4. C# Delegates Series Part 4 - Delegates can be used to Invoke methods asynchronously

Delegates are the base for Event handling mechanism in .net framework. Consider an example of Button Click event. Let’s see below code.

C# - Windows Forms

public Form1()
{
InitializeComponent();
btnSave.Click += btnSave_Click;
}

private void btnSave_Click(object sender, EventArgs e)
{

}

WPF

public MainWindow()
{
InitializeComponent();
btnSave.Click += btnSave_Click;
}

private void btnSave_Click(object sender, RoutedEventArgs e)
{

}

Here Click is the event of Button. btnSave_Click is the event handler/method that will be executed when button is clicked. Above syntax is called wiring event with event handler/method.


Now if we see the definition of button Click event  (Place cursor over Click keyword and Press F12 or right click on Click keyword and select go to definition), we find below code.


C# – Windows forms

public event EventHandler Click;

Drill down further to definition of EventHandler and we see below.

public delegate void EventHandler(object sender, EventArgs e);

So EventHandler is of type delegate that takes 2 arguments and returns nothing. Now if we see our definition of BtnSave method this would match with signature of delegate.


WPF

public event RoutedEventHandler Click;

Drill down further to definition of RoutedEventHandler and we see below.

public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);

So RoutedEventHandler is of type delegate that takes 2 arguments and returns nothing. Now if we see our definition of BtnSave method this would match with signature of delegate.


That’s all about .net framework, now we see a real life example where we would find this useful.


There can be several examples.


Suppose you are designing a Login UserControl that takes login information from User. When user click OK button, you want en event to be fired on parent control (hosting Login UserControl) for further/additional processing.


In this post, we extend an example of our previous post where we created a Form that displays list of Assets. When user selects an Asset and clicks OK button, an event is fired in parent control (control that opened this Assets form) and selected asset information is passed to parent control.


Below is the code to achieve this functionality using delegates and events. In this post, we take an example of WPF application. Download the attached sample for complete example in C# console application, Windows forms and WPF.


Assets.xaml.cs


Assets page will load and displays list of assets in DataGrid. When user selects an asset in DataGrid and clicks OK button, an event should be fired in calling window that invoked Assets window. To achieve this we declare a delegate that can hold reference to method with one argument and returns no value. Then we create an event based on this delegate.

// Declare delegate
public delegate void AssetSelectedEventHandler(AssetItem item);

// Create event based on delegate
public event AssetSelectedEventHandler AssetSelected;

When user clicks OK button, we check if parent control (MainWindow in this case) has subscribed to this event by comparing AssetSelected to null and then we raise the AssetSelected event with argument as selected asset.

private void btnOK_Click(object sender, RoutedEventArgs e)
{
if (AssetSelected != null)
AssetSelected((AssetItem)AssetsGrid.SelectedItem);

this.Close();
}

MainWindow.xaml.cs


This is the main window that is displayed when application is started. In MainWindow, we load Assets.xaml window.

Assets assetSelector = new Assets(FilterMethod);
assetSelector.Owner = this;
assetSelector.AssetSelected += assetSelector_AssetSelected;
assetSelector.ShowDialog();
private void assetSelector_AssetSelected(AssetItem item)
{
// Here we get selected AssetItem information.
}

Code highlighted in yellow shows that “AssetSelected” event defined in Assets.xaml is attached to the event handler “assetSelector_AssetSelected”. Hence when AssetSelected event is raised in Assets.xaml window, assetSelector_AssetSelected event handler is called in MainWindown.xaml

No comments:

Post a Comment