Using Delegates to Communication Between Windows Forms

Introduction

Delegates are one of the wonderful features of .Net Framework. Their primary use is focused on support event handling and callback mechanism. In this article, we will explore how to use delegate as callback support to make simple communication between different opened windows forms.

In this article, I assume that you know the definition of delegate and its primary use in .Net Framework.

Scenario overview

In many scenarios, a windows form is used to open some other windows forms as modal or non-modal. The newly opened form or the opener itself (the parent form) may need to send each other some notifications or values. For example, you select a value from a ComboBox on the newly opened form, and you want to send this value immediately on select to the opener parent form. Or you changed a parameter value in the opener form (parent) that the newly opened form depends on. Such scenarios can be implemented using delegates in form of callbacks.

Scenario in action

We are going to explore 2 scenarios:

  • First Scenario: The main windows form (parent) that can open deferent instances of other windows forms (children).

    The parent form will contain a TextBox, when the text in this text box changes, all opened windows forms (children) should be notified with this change and display it.
     
  • Second Scenario: The main windows form (parent) that contains a ListBox will open a dialog form that contains a TextBox with two buttons (Add Item) & (Close). Whenever the user click the Add Item button, the item should be added to the ListBox in the main form without closing the dialog. Close button should close the dialog.

Of course these scenarios can be done by exposing controls as public instances. But many would prefer to keep controls as private and start using delegates

The Rule

First of all, you need to decide what do you want to send to the other form cause this will lead you to decide what is parameter type you will use in your delegate.

In our case here, we need only to pass string, so we need to define delegate with string as parameter for example:

public delegate void SetParameterValueDelegate(string value);

Second, you need to decide who is the owner of the communication, in other words, which form will send the notification?! In our first scenario the main form (parent) will be the owner of the communication. But in the second scenario the dialog form will be the owner.

Once you decide the owner, you'll need to declare an instance of your delegate type inside the owner class for example:

public SetParameterValueDelegate SetParameterValueCallback;

The other forms will be subscribers for the callback (delegate), only if you wish to send notification to them.

The First Scenario

The following screenshot shows the first scenario in action, just to note the simple user interface we are using to demonstrate the example:

scenario01.jpg

You need to declare a delegate, should be outside any class for our example needs.

Listing 01-Declare a delegate:

public delegate void SetParameterValueDelegate(string value);

The following is the code written in the Main From "FrmMain Class":

Listing 02-FrmMain Class:

//Declare delagete callback function, the owner of communication
public SetParameterValueDelegate SetParameterValueCallback;
private void btnOpenFrm1_Click(object sender, EventArgs e)
{
    FrmChild1 frm = new FrmChild1();
    //Subscribe frm for Callback
    this.SetParameterValueCallback += new SetParameterValueDelegate(frm.SetParamValueCallbackFn);
    frm.Show();
}
private void btnOpenFrm2_Click(object sender, EventArgs e)
{
    FrmChild2 frm = new FrmChild2();
    //Subscribe frm for Callback
    this.SetParameterValueCallback += new SetParameterValueDelegate(frm.SetParamValueCallbackFn);
    frm.Show();
}
private void txtParam_TextChanged(object sender, EventArgs e)
{
    //Send Notification to all subscribers
    SetParameterValueCallback(txtParam.Text);
}

Did you note the frm.SetParamValueCallbackFn?! Well this is method defined in both FrmChild1 & FrmChild2 forms, of course the method can have different names on each class.

What you should know and note, this method should have the same signature as the delegate, which means, the delegate is void, your method should be void, the delegate accepts only one string parameter, your method also should accept only one string parameter.

The following shows the definition of the SetParamValueCallbackFn method:

Listing 03-SetParamValueCallbackFn Method:

public void SetParamValueCallbackFn(string param)
{
    txtParam.Text = param;
}

The Second Scenario

You might guess what we should do in this scenario, first we will create a new delegate that takes a string parameter, we will call it AddItemDelegate. In the Dialog form (FrmDialog) we will declare a callback method of type AddItemDelegate. In main from (FrmMain) we will define the callback function.

Listing 04-AddItemDelegate:

public delegate void AddItemDelegate(string item);

Listing 05-FrmDialog Class:

//Declare delagete callback function, the owner of communication
public AddItemDelegate AddItemCallback;
private void btnAdd_Click(object sender, EventArgs e)
{
    //Notification subscribers
    AddItemCallback(txtItem.Text);
}

Listing 06-FrmMain Class:

private void btnScenario2_Click(object sender, EventArgs e)
{
    FrmDialog dlg = new FrmDialog();
    //Subscribe this form for callback
    dlg.AddItemCallback = new AddItemDelegate(this.AddItemCallbackFn);
    dlg.ShowDialog();
}
private void AddItemCallbackFn(string item)
{
    lstBx.Items.Add(item);
}

scenario02.jpg

Conclusion

The way of using delegates to send information between windows forms is much more clear than exposing controls as public instances, well this is my opinion.

In the examples represented here, we could use on delegate instead of tow, but I represented this just for clarification. Hope you find it useful.