Professional Documents
Culture Documents
Introduction
Abstraction problems of methods and functions
How to declare a delegate?
Solving the abstract pointer problem using delegates
Multicast delegates
Simple demonstration of multicast delegates
Problem with multicast delegates – naked exposure
Events – Encapsulation on delegates
Implementing events
Difference between delegates and events
Delegates for Asynchronous method calls
Summarizing Use of delegates
Difference between delegates and C++ pointer
Source code
Introduction
In this article we will first try to understand what problem delegate solves, we will then create a simple delegate and try to solve
the problem. Next we will try to understand the concept of multicast delegates and how events help to encapsulate delegates.
Finally we understand the difference between events and delegates and also understand how to do invoke delegates
asynchronously.
Once we are done with all fundamentals we will summarize the six important uses of delegates.
This is a small Ebook for all my .NET friends which covers topics like WCF,WPF,WWF,Ajax,Core .NET,SQL etc you can
download the same from
http://tinyurl.com/4nvp9t or else you can catch me on my daily free training @ http://tinyurl.com/39m4ovr
Before we move ahead and we talk about delegates let's try to understand what problem does delegate solve. Below is a simple
class named 'ClsMaths' which has a simple 'Add' function. This class 'ClsMaths' is consumed by a simple UI client. Now let's say
over a period of time you add subtraction functionality to the 'ClsMaths' class, your client need to change accordingly to
accommodate the new functionality.
In other words addition of new functionality in the class leads to recompiling of your UI client.
In short the problem is that there is a tight coupling of function names with the UI client. So how can we solve this problem?.
Rather than referring to the actual methods in the UI / client if we can refer an abstract pointer which in turn refers to the methods
then we can decouple the functions from UI.
Later any change in the class 'ClsMath' will not affect the UI as the changes will be decoupled by the Abstract pointer. This
abstract pointer can be defined by using delegates. Delegates define a simple abstract pointer to the function / method.
Ok, now that we have understood the tight coupling problem and also the solution, let's try to understand how we can define a
simple delegate.
To implement a delegate is a four step process declare, create, point and invoke.
The first step is to declare the delegate with the same return type and input parameters. For instance the below function 'add' has
two input integer parameters and one integer output parameter.
private int Add(int i,int y)
{
return i + y;
}
So for the above method the delegate needs to be defined in the follow manner below. Please see the delegate keyword attached
with the code.
// Declare delegate
public delegate int PointetoAddFunction(int i,int y);
The return type and input type of the delegate needs to be compatible, in case they are not compatible it will show the below error
as shown in the image below.
The third step is to point the delegate reference to the method, currently we need to point the delegate reference to the add
function.
Finally we need to invoke the delegate function using the "Invoke" function of the delegate.
Below figure sums up how the above four step are map with the code snippet.
In order to decouple the algorithm changes we can expose all the below arithmetic function through an abstract delegate.
So the first step is to add a generic delegate which gives one output and takes two inputs as shown in the below code snippet.
public class clsMaths
{
public delegate int PointerMaths(int i, int y);
}
The next step is to expose a function which takes in operation and exposes an attached delegate to the UI as shown in the below
code snippet.
Below is how the complete code snippet looks like. All the algorithm functions i.e. 'Add' , 'Sub' etc are made private and only one
generic abstract delegate pointer is exposed which can be used to invoke these algorithm function.
So at the client side the calls becomes generic without any coupling with the actual method names like 'Add' , 'Sub' etc.
Multicast delegates
In our previous example we have see how we can create a delegate pointer to a function or method. We can also create a delegate
which can point to multiple functions and methods. If we invoke such delegate it will invoke all the methods and functions
associated with the same one after another sequentially.
Below is the code snippet which attaches 2 methods i.e. method1 and method2 with delegate 'delegateptr'. In order to add multiple
methods and function we need to use '+=' symbols. Now if we invoke the delegate it will invoke 'Method1' first and then
'Method2'. Invocation happen in the same sequence as the attachment is done.
// Associate method1
delegateptr += Method1;
// Associate Method2
delegateptr += Method2;
// Invoke the Method1 and Method2 sequentially
delegateptr.Invoke();
So how we can use multicast delegate in actual projects. Many times we want to create publisher / subscriber kind of model. For
instance in an application we can have various error logging routine and as soon as error happens in a application you would like
to broadcast the errors to the respective components.
In order to understand multicast delegates better let's do the below demo. In this demo we have 'Form1', 'Form2' and 'Form3'.
'Form1' has a multicast delegate which will propagate event to 'Form2' and 'Form3'.
At the form level of 'Form1' (this form will be propagating events to form2 and form3) we will first define a simple delegate and
reference of the delegate as shown in the code snippet below. This delegate will be responsible for broadcasting events to the other
forms.
In the form load we invoke the forms and attach 'CallMe' method which is present in both the forms in a multicast fashion ( += ).
Finally we can invoke and broadcast method calls to both the forms.
The first problem with above code is that the subscribers (form2 and form3) do not have the rights to say that they are interested
or not interested in the events. It's all decided by 'form1'.
We can go other route i.e. pass the delegate to the subscribers and let them attach their methods if they wish to subscribe to the
broadcast sent by 'form1'. But that leads to a different set of problems i.e. encapsulation violation.
If we expose the delegate to the subscriber he can invoke delegate, add his own functions etc. In other words the delegate is
completely naked to the subscriber.
Events help to solve the delegate encapsulation problem. Events sit on top of delegates and provide encapsulation so that the
destination source can only listen and not have full control of the delegate object.
Below figure shows how the things look like:-
• Method and functions are abstracted /encapsulated using delegates
• Delegates are further extended to provide broadcasting model by using multicast delegate.
• Multicast delegate are further encapsulated using events.
Implementing events
So let's take the same example which we did using multicast delegates and try to implement the same using events. Event uses
delegate internally as event provides higher level of encapsulation over delegates.
So the first step in the publisher ('Form1') we need to define the delegate and the event for the delegate. Below is the code snippet
for the same and please do notice the 'event' keyword.
We have defined a delegate 'CallEveryOne' and we have specified an event object for the delegate called as 'EventCallEveryOne'.
From the publisher i.e. 'Form1' create 'Form2' and 'Form3' objects and attach the current 'Form1' object so that 'Form2' and 'Form3'
will listen to the events. Once the object is attached raise the events.
At the subscriber side i.e. (Form2 and Form3) attach the method to the event listener.
obj.EventCallEveryOne += Callme;
This code will show the same results as we have got from multicast delegate example.
One of the other uses of delegates is asynchronous method calls. You can call methods and functions pointed by delegate
asynchronously.
Asynchronous calling means the client calls the delegate and the control is returned back immediately for further execution. The
delegate runs in parallel to the main caller. When the delegate has finished doing his work he makes a call back to the caller
intimating that the function / subroutine has completed executing.
To invoke a delegate asynchronously we need call the 'begininvoke' method. In the 'begininvoke' method we need to specify the
call back method which is 'CallbackMethod' currently.
Below is the code snippet for 'CallbackMethod'. This method will be called once the delegate finishes his task.
This is the most important use of delegates; it helps us to define an abstract pointer which can point to methods and functions. The
same abstract delegate can be later used to point to that type of functions and methods. In the previous section we have shown a
simple example of a maths class. Later addition of new algorithm functions does not affect the UI code.
2. Callback mechanism
Many times we would like to provide a call back mechanism. Delegates can be passed to the destination and destination can use
the same delegate pointer to make callbacks.
3. Asynchronous processing
By using 'BeginInvoke' and 'EndInvoke' we can call delegates asynchronously. In our previous section we have explained the
same in detail.
Introduction
In this article I will walk you through how to create different forms and access form from other forms.
While we are developing I will help you to understand modal and modeless forms and some important
control properties.
We will create three forms. One is a Main form that will invoke and display an About form and an
Address Form. The About form is invoked as Modeless dialog and the Address Form is invoked as a
Modal dialog.
Main Form
First we will design the Main form that invokes two other forms. Follow the steps below:
1. Open visual studio 2005 and create a new Visual C# Windows Application.
2. Use the following picture as the reference for creating the Form
I marked all the controls with some numbers to ask you to make some changes for the corresponding
controls.
1: TextBox Control. Actually no property change is required for this text box. When I am
creating the picture I forgot it and kept a number for it. So leave it as default
2: Button Control. Change the Name property to btnGetAddress
4: Button Control. Change the Name property to btnAbout
3: TextBox Control. Change the Name property to txtAddress. Set MultiLine to true. This will
allow you resize the text box to have different height. When MultiLine property is false the
resize in terms of Height is not allowed. Set the ReadOnly to true. When set to true this
property does not allow the control to be editable by the end user. But, you can edit it
through the code at runtime. Change the BackColor property to White as the ReadOnly
property changed it to some Gray color.
If you wish you can set the Background and foreground colors as you like.
This is the second form that we are going to add to our project. When you created the Windows
Application, the wizard created a main form for us and that for us is the Start Up form.
Suppose if you want to change the Startup form, what will you do?
Double click the Program.cs file and scroll to find the following piece of code:
The Application.Run method takes our Main form Object and displays it. I renamed the form1 to
frmMain by right clicking it in the solution explorer and using the Rename menu option.
1) Goto the solution Explorer using View|Solution Explorer if it is already not available on your right
side pane.
2) Select the solution Name, right click on it, and chose Add|New Item
3) In the displayed dialog select Windows Form and Change the File Name to frmAbout.cs
4) Place a Label control on the Form. Set the Text property as shown in the Picture below. Note, you
need to use the Down Arrow button of the text property value to type multiple lines for the label. The
screen shot is shown below:
Now we will add a new form and display it like Modal dialog. Follow the Steps below and I will tell you
what is Modal dialog and Modeless dialog when you run the finished application.
1) Add a new Windows form as you did in the previously. Name the file as AddressDlg.cs
2) Place 5 Labels and 5 Text boxes to the Form. Add two button controls
3) Arrange the Form as shown below:
1: Set the Name property to txtDoorNumber
2: Set the Name property to txtStreet
3: Set the Name property to txtArea
4: Set the Name property to txtCity
5: Set the Name property to txtPin
7: Set the Name property to btnOK. Set the text property to OK. And select OK as the
DialogResult Property.
8: Set the Name property to btnCancel. Set the text property to OK. And select Cancel as the
DialogResult Property.
9: Set the Name property to AddressDlg. Select btnOK for the AcceptButton property. Select
btnCancel for the CancelButton property.
We are done with designing the Address form. Now let me explain about the above form. As I already
said, we are going to display the above form as modal. What is the difference between modal and
modeless dialogs (or forms)?
When we display a form as Modeless, you can still access the Main form that called the Modeless
dialog. But, the access to the Main form is prohibited when we display the same dialog as Modal. Let
us say the Instance of the above dialog as X, X.Show() will display the dialog as modeless where as
X.ShowDialog() will display the dialog as Modal. If you remember, in this Article we are going to
display the About form as Modeless and Address form as Modal.
We set btnOK as AcceptButton and btnCancel as the Cancelbutton properties for the form. This is to
hook-up the Esc and Enter keystrokes on the form to the OK and Cancel button clicks. So hitting enter
button on the form runs the OK button event handler. Hitting Esc will run the cancel button event
handler.
The ShowDialog() function will return some constants based on how the form is closed (actually
hidden) by the interacting user. We can set these constants to the button on the form. We set
DialogResult property for the button btnOK as OK, and for the button btnCancel as Cancel. For
example if the user closes the dialog by clicking the btnOK the constant OK is passed back to the
caller.
Hope all the designs are done now. If you need you can open the attached project for reference. Open
the forms and look at the properties that appear in bold.
//004_Model: Invoke the Model Dialog and set the Readonly Address
//Text box
AddressDlg dlg = new AddressDlg();
if (dlg.ShowDialog() == DialogResult.OK)
txtAddress.Text = dlg.Address;
else
txtAddress.Text = "---";
After creating the instance (dlg) of AddressDlg we are displaying the dialog as a modal dialog. This
we use the method ShowDialog() and the call to this method block the calling code until the dialog is
closed. The return value of function (the value you set for the button's DialogResult property) is
checked to make sure OK button is clicked by the user. In that case (OK button click) we take the
Address property from dialog and display it in the Multi Line text box Address.
Note that all the controls in the Form are Private. If you need you can change it by setting the Modifier
property of the control, which is not advisable. I do expose a property Address, which stores the
values, entered by the user in the text fields.
3) Next add a public property that give access to the Address field
//001_Model: Set the Address Member variable based on the User Input
mAddress = txtDoorNumber.Text + ";" + txtStreet.Text + Environment.NewLine +
txtArea.Text + Environment.NewLine + txtCity.Text + Environment.NewLine +
"Pin -" + txtPin.Text;
We store all the Address parts in the local private field by combining all the text values entered in the
form. And, we do this on the handler for OK button click, as we know all the texts are ready from user
perspective. The Address property is public and gives access to the Field mAddress for external world.
The displayed address form blocks the caller from the main form. When the address form is closed, the
main form can again receive user input.
5) Type in the Address Parts and Close the Dialog. [ You can try Esc and Hitting Enter and Clicking
cancel. ]