40
Interrupting Program Flow and Handling Events Binay DEMİR Visual C# 2010 Microsoft

Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Embed Size (px)

Citation preview

Page 1: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Interrupting Program Flow and Handling Events

Binay DEMİR

Visual C# 2010 Microsoft

Page 2: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Interrupting Program Flow and Handling Events

Interrupting the current flow of execution and performing other sometimes is a very important . The application has to temporarily stop what it is doing and handle user input.

To handle this type of application, the runtime has to provide two things: a means of indicating that something urgent has happened and a way of specifying the code that should be run when it happens. This is the purpose of events and delegates.

Page 3: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Declaring And Using Delegates

What is a delegate?

Advantages

Encapsulating the method's call from caller

Effective use of delegate improves the performance of application

Used to call a method asynchronously

Delegate is a type which holds the method(s) reference in an object. It is also referred to as a type safe function pointer.

Page 4: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Sample Program Using Delegate

public delegate double Delegate_Prod(int a,int b); class Class1 { static double fn_Prodvalues(int val1,int val2) { return val1*val2; } static void Main(string[] args) { //Creating the Delegate Instance Delegate_Prod delObj = new Delegate_Prod(fn_Prodvalues); Console.Write("Please Enter Values"); int v1 = Int32.Parse(Console.ReadLine()); int v2 = Int32.Parse(Console.ReadLine()); //use a delegate for processing double res = delObj(v1,v2); Console.WriteLine ("Result :"+res); Console.ReadLine(); } }

Page 5: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

The Automated Factory Scenario

motor control and drive system, robotics system, machine vision system, programmable logic control system and manufacturing executive systems.

Factory automation is based on the application of computers. It involves various technologies. The technologies involves in factory automation are;

These are also known as automation tools without which automation is not possible. There is need to unify the business with plant floor system in the present global scenario. The factory automation makes it possible.

Page 6: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory Without Using Delegates

A simple approach to implementing the shutdown functionality in the control

program is as follows:

class Controller { // Fields representing the different machines private FoldingMachine folder; private WeldingMachine welder; private PaintingMachine painter; ... public void ShutDown() { folder.StopFolding(); welder.FinishWelding(); painter.PaintOff(); } ... }

Page 7: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory Without Using Delegates

In most cases, when we call a function, we specify the function to be called directly. If the class MyClass has a function named Process, we'd normally call it like this: using System; namespace Akadia.NoDelegate { public class MyClass { public void Process() { Console.WriteLine("Process() begin"); Console.WriteLine("Process() end"); } } public class Test { static void Main(string[] args) { MyClass myClass = new MyClass(); myClass.Process(); } } }

Page 8: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory Without Using Delegates

That works well in most situations. Sometimes, however, we don't want to call a function directly - we'd like to be able to pass it to somebody else so that they can call it. This is especially useful in an event-driven system such as a graphical user interface, when I want some code to be executed when the user clicks on a button, or when I want to log some information but can't specify how it is logged.

Page 9: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

The general format of each method, therefore, is this

void methodName();

We declare a delegate like this;

delegate void stopMachineryDelegate();

We can create an instance and make it refer to a matching method by using the +=

compound assignment operator. We can do this in the constructor of the controller class

like this:

Page 10: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

class Controller { delegate void stopMachineryDelegate(); private stopMachineryDelegate stopMachinery; // an instance of the delegate ... public Controller() { this.stopMachinery += folder.StopFolding; } ... }

Page 11: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

It is safe to use the += operator on an uninitialized delegate. It will be initialized

automatically.

Alternatively, we can also use the new keyword to initialize a delegate explicitly with a

single specific method, like this: this.stopMachinery = new stopMachineryDelegate(folder.StopFolding);

We can call the method by invoking the delegate, like this:

public void ShutDown() { this.stopMachinery(); ... }

Page 12: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

The principal advantage of using a delegate is that it can refer to more than one method;

we simply use the += operator to add methods to the delegate, like this:

public Controller() { this.stopMachinery += folder.StopFolding; this.stopMachinery += welder.FinishWelding; this.stopMachinery += painter.PaintOff; }

We can remove a method from a delegate by using the –= compound assignment

operator:

this.stopMachinery -= folder.StopFolding;

Page 13: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

The current scheme adds the machine methods to the delegate in the Controller

constructor. To make the Controller class totally independent of the various machines, we

need to make stopMachineryDelegate type public and supply a means of enabling

classes outside Controller to add methods to the delegate.

We have several options:

• Make the delegate variable, stopMachinery, public :

public stopMachineryDelegate stopMachinery;

• Keep the stopMachinery delegate variable private, but provide a read/write property to

provide access to it:

Page 14: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

public delegate void stopMachineryDelegate();

...

public stopMachineryDelegate StopMachinery

{

get

{

return this.stopMachinery;

}

set

{

this.stopMachinery = value;

}

}

Page 15: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

• Provide complete encapsulation by implementing separate Add and Remove methods.

The Add method takes a method as a parameter and adds it to the delegate, while

the Remove method removes the specified method from the delegate (notice that we

specify a method as a parameter by using a delegate type):

public void Add(stopMachineryDelegate stopMethod)

{

this.stopMachinery += stopMethod;

}

public void Remove(stopMachineryDelegate stopMethod)

{

this.stopMachinery -= stopMethod;

}

Page 16: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Implementing the Factory by Using a Delegate

Whichever technique we choose, we should remove the code that adds the machine

Methods to the delegate from the Controller constructor. we can then instantiate a

Controller and objects representing the other machines like this (this example uses the

Add/Remove approach):

Controller control = new Controller();

FoldingMachine folder = new FoldingMachine();

WeldingMachine welder = new WeldingMachine();

PaintingMachine painter = new PaintingMachine();

...

control.Add(folder.StopFolding);

control.Add(welder.FinishWelding);

control.Add(painter.PaintOff);

...

control.ShutDown();

...

Page 17: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Delegates

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

delegate void MyDelegate(string s);

class MyClass

{

public static void Hello(string s)

{

Console.WriteLine(" Hello, {0}!", s);

}

public static void Goodbye(string s)

{

Console.WriteLine(" Goodbye, {0}!", s);

}

Page 18: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Delegates

public static void Main()

{

MyDelegate a, b, c, d;

// Create the delegate object a that references

// the method Hello:

a = new MyDelegate(Hello);

// Create the delegate object b that references

// the method Goodbye:

b = new MyDelegate(Goodbye);

// The two delegates, a and b, are composed to form c:

c = a + b;

// Remove a from the composed delegate, leaving d,

// which calls only the method Goodbye:

d = c - a;

Console.WriteLine("Invoking delegate a:");

a("A");

Console.WriteLine("Invoking delegate b:");

b("B");

Console.WriteLine("Invoking delegate c:");

c("C");

Console.WriteLine("Invoking delegate d:");

d("D");

}

}

Page 19: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Delegates

This example demonstrates composing delegates. A useful property of delegate objects is that

they can be composed using the "+" operator. A composed delegate calls the two delegates it was

composed from. Only delegates of the same type can be composed.

The "-" operator can be used to remove a component delegate from a composed delegate.

A very basic example :

using System;

namespace Akadia.BasicDelegate

{

// Declaration

public delegate void SimpleDelegate();

class TestDelegate

{

public static void MyFunc()

{

Console.WriteLine("I was called by delegate ...");

}

Page 20: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Delegates

public static void Main()

{

// Instantiation

SimpleDelegate simpleDelegate = new SimpleDelegate(MyFunc);

// Invocation

simpleDelegate();

}

}

}

Page 21: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Lambda Expressions and Delegates

All the examples of adding a method to a delegate that we have seen so far use the

method’s name. For example, returning to the automated factory scenario described

earlier, we add the StopFolding method of the folder object to the stopMachinery delegate

like this:

this.stopMachinery += folder.StopFolding;

This approach is very useful if there is a convenient method that matches the signature of

the delegate, but what if this is not the case? Suppose that the StopFolding method

actually had the following signature:

void StopFolding(int shutDownTime); // Shut down in the specified number of seconds

This signature is now different from that of the FinishWelding and PaintOff methods, and

therefore we cannot use the same delegate to handle all three methods. So, what do

we do?

Page 22: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Creating a Method Adapter

One way around this problem is to create another method that calls StopFolding but that

takes no parameters itself, like this:

void FinishFolding()

{

folder.StopFolding(0); // Shut down immediately

}

we can then add the FinishFolding method to the stopMachinery delegate in place of the

StopFolding method, using the same syntax as before:

this.stopMachinery += folder.FinishFolding;

When the stopMachinery delegate is invoked, it calls FinishFolding, which in turn calls the

StopFolding method, passing in the parameter of 0.

Page 23: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using a Lambda Expression as an Adapter

A lambda expression contains two of these elements: a list of parameters and a method

body.

Lambda expressions do not define a method name, and the return type (if any) is inferred

from the context in which the lambda expression is used. In the StopFolding method of

the FoldingMachine class, the problem is that this method now takes a parameter, so we

need to create an adapter that takes no parameters that we can add to the

stopMachinery delegate.

We can use the following statement to do this:

this.stopMachinery += (() => { folder.StopFolding(0); });

Page 24: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using a Lambda Expression as an Adapter

The body of a lambda expression can be a method body containing

multiple statements, or it can actually be a single expression. If the body of a lambda

expression contains only a single expression, we can omit the braces and the semicolon

(but we still need a semicolon to complete the entire statement), like this:

this.stopMachinery += (() => folder.StopFolding(0));

When we invoke the stopMachinery delegate, it will run the code defined by the lambda

expression.

Page 25: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

The Form of Lambda Expressions

A lambda expression is an anonymous function that we can use to create delegates or

expression tree types. By using lambda expressions, we can write local functions that

can be passed as arguments or returned as the value of function calls. Lambda

expressions are particularly helpful for writing LINQ query expressions.

To create a lambda expression, we specify input parameters (if any) on the left side of the

lambda operator =>, and we put the expression or statement block on the other side. For

example, the lambda expression x => x * xspecifies a parameter that’s named x and

returns the value of x squared. we can assign this expression to a delegate type, as the

following example shows

Page 26: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

The Form of Lambda Expressions

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

namespace Akadia.BasicDelegate

{

// Declaration

public delegate void SimpleDelegate();

class TestDelegate

{

delegate int del(int i);

static void Main(string[] args)

{

del myDelegate = x => x * x;

int j = myDelegate(5); //j = 25

}

}

}

Page 27: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

The Form of Lambda Expressions

To create an expression tree type:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Linq.Expressions;

namespace ConsoleApplication1

{

class Program

{

delegate int del(int i);

static void Main(string[] args)

{

Expression<del> myET = x => x * x;

}

}

}

Page 28: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Enabling Notifications with Events

we declare an event similarly to how we declare a field. However, because events are

İntended to be used with delegates, the type of an event must be a delegate, and we

must prefix the declaration with the event keyword. Use the following syntax to declare an

event:

event delegateTypeName eventName

As an example, here’s the StopMachineryDelegate delegate from the automated factory.

It has been relocated to a new class called TemperatureMonitor, which provides an

interface to the various electronic probes monitoring the temperature of the equipment

(this is a more logical place for the event than the Controller class is):

class TemperatureMonitor

{

public delegate void StopMachineryDelegate();

...

}

Declaring an Event

Page 29: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Enabling Notifications with Events

We can define the MachineOverheating event, which will invoke the

stopMachineryDelegate, like this:

class TemperatureMonitor

{

public delegate void StopMachineryDelegate();

public event StopMachineryDelegate MachineOverheating;

...

}

Declaring an Event

Page 30: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Enabling Notifications with Events

We can define the MachineOverheating event, which will invoke the Like delegates, events come

ready-made with a += operator. we subscribe to an event by

using this += operator. In the automated factory, the software controlling each machine

can arrange for the shutdown methods to be called when the MachineOverheating event is raised, like

this:

class TemperatureMonitor

{

public delegate void StopMachineryDelegate();

public event StopMachineryDelegate MachineOverheating;

...

}

...

TemperatureMonitor tempMonitor = new TemperatureMonitor();

...

tempMonitor.MachineOverheating += (() => { folder.StopFolding(0); });

tempMonitor.MachineOverheating += welder.FinishWelding;

tempMonitor.MachineOverheating += painter.PaintOff;

Subscribing to an Event

Page 31: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Enabling Notifications with Events

An event can be raised, just like a delegate, by calling it like a method. When we raise

an event, all the attached delegates are called in sequence. For example, here’s the

TemperatureMonitor class with a private Notify method that raises the

MachineOverheating event:

class TemperatureMonitor

{

public delegate void StopMachineryDelegate();

public event StopMachineryDelegate MachineOverheating;

...

private void Notify()

{

if (this.MachineOverheating != null)

{

this.MachineOverheating();

}

}

...

}

Raising an Event

Page 32: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Understanding WPF User Interface Events

The WPF Button class derives from the ButtonBase class, inheriting a public event called

Click of type RoutedEventHandler. The RoutedEventHandler delegate expects two

parameters: a reference to the object that caused the event to be raised and a

RoutedEventArgs object that contains additional information about the event:

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

The Button class looks like this:

public class ButtonBase: ...

{

public event RoutedEventHandler Click;

...

}

public class Button: ButtonBase

{

...

}

Page 33: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Understanding WPF User Interface Events

The Button class automatically raises the Click event when we click the button on-

screen.(How this actually happens is beyond the scope of this book.) This arrangement

makes it easy to create a delegate for a chosen method and attach that delegate to the

required event. The following example shows the code for a WPF form that contains a

button called okay and the code to connect the Click event of the okay button to the

okayClick method:

public partial class Example : System.Windows.Window, System.Windows.Markup.

IComponentConnector

{

internal System.Windows.Controls.Button okay;

...

void System.Windows.Markup.IComponentConnector.Connect(...)

{

...

this.okay.Click += new System.Windows.RoutedEventHandler(this.okayClick);

...

}

...

}

Page 34: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Understanding WPF User Interface Events

This code is usually hidden from we. When we use the Design View window in Visual

Studio 2010 and set the Click property of the okay button to okayClick in the Extensible

Application Markup Language (XAML) description of the form, Visual Studio 2010

generates this code for we. All we have to do is write wer application logic in the event

handling method, okayClick, in the part of the code that we do have access to, in the

Example.xaml.cs file in this case: public partial class Example : System.Windows.Window

{

...

private void okayClick(object sender, RoutedEventArgs args)

{

// wer code to handle the Click event

}

}

Page 35: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Events

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Linq.Expressions;

namespace wildert

{

public class Metronome

{

public event TickHandler Tick;

public EventArgs e = null;

public delegate void TickHandler(Metronome m, EventArgs e);

public void Start()

{

while (true)

{

System.Threading.Thread.Sleep(3000);

if (Tick != null)

{

Tick(this, e);

}

}

}

Page 36: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Events

public class Listener

{

public void Subscribe(Metronome m)

{

m.Tick += new Metronome.TickHandler(HeardIt);

}

private void HeardIt(Metronome m, EventArgs e)

{

System.Console.WriteLine("HEARD IT");

}

}

class Test

{

static void Main()

{

Metronome m = new Metronome();

Listener l = new Listener();

l.Subscribe(m);

m.Start();

}

}

}

Page 37: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Events

A slightly more complicated example is if the event has

information passed with it, such as mouse coordinates for a

mouse event or which key is pressed for a keypress event. To do this

we need to create an appropriate class derived from

the EventArgs class and then set an instance of it before raising

the event. See below:

Page 38: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Events

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Linq.Expressions;

namespace wildert

{

public class TimeOfTick : EventArgs

{

private DateTime TimeNow;

public DateTime Time

{

set

{

TimeNow = value;

}

get

{

return this.TimeNow;

}

}

}

Page 39: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Events

public class Metronome

{

public event TickHandler Tick;

public delegate void TickHandler(Metronome m, TimeOfTick e);

public void Start()

{

while (true)

{

System.Threading.Thread.Sleep(3000);

if (Tick != null)

{

TimeOfTick TOT = new TimeOfTick();

TOT.Time = DateTime.Now;

Tick(this, TOT);

}

}

}

}

Page 40: Microsoft Visual C# 2010 - EEMB DERSLER · PDF fileVisual C# 2010 Microsoft . Interrupting Program Flow and Handling Events Interrupting the current flow of execution and performing

Using Events

public class Listener

{

public void Subscribe(Metronome m)

{

m.Tick += new Metronome.TickHandler(HeardIt);

}

private void HeardIt(Metronome m, TimeOfTick e)

{

System.Console.WriteLine("HEARD IT AT {0}", e.Time);

}

}

class Test

{

static void Main()

{

Metronome m = new Metronome();

Listener l = new Listener();

l.Subscribe(m);

m.Start();

}

}

}