DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Building Modern 3factor Apps in 2021 With Event-Driven Programming
  • Event Driven Architecture (EDA) - Optimizer or Complicator
  • Event-Driven Microservices: How Kafka and RabbitMQ Power Scalable Systems
  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes

Trending

  • Memory-Optimized Tables: Implementation Strategies for SQL Server
  • Designing for Sustainability: The Rise of Green Software
  • Mastering Advanced Traffic Management in Multi-Cloud Kubernetes: Scaling With Multiple Istio Ingress Gateways
  • Designing AI Multi-Agent Systems in Java

Introduction to Event Driven Programming in C#

By 
Richard Mccutchen user avatar
Richard Mccutchen
·
May. 31, 10 · Interview
Likes (0)
Comment
Save
Tweet
Share
61.2K Views

Join the DZone community and get the full member experience.

Join For Free

At one point in our careers we've all been introduced to, or at least heard of, event driven programming, programming where the overall flow of the application is controlled by user generated events. In C# event driven programming is made much easier with the offering of Delegates & Events. So today we're going to look at event driven programming in C#. Before we get into the meat of event driven programming we need to set a couple definitions for terms we will be using in this article:


Delegate:

A delegate is very similar to a function pointer in C++. It is a reference type that encapsulates a method which has a specific signature and a return type.


Events:

An event allows a class (or other object) to send notifications to other classes (or objects) that something has occurred. In simple terms an event is the outcome of a specific action.


In the old days all programs were very linear, they followed a set of commands/paths and user interaction was merely an after-thought, or limited to filling in forms or providing data. Over time things have changed drastically, todays programs are more user driven than ever, and as developers we need to change & adapt to this. In todays environment we as developers know that actions are going to need to be taken, but at design-time we do not know what order these actions are going to occur, because it's all dependent on what actions the users take. We know we're going to have to execute an action, but until the user makes their action we dont know which method (or event) is supposed to be executed. That's where event driven programming comes into play. With events & delegates we can make these decisions on the fly.


So how exactly do delegates & events help with event driven programming you may ask? Well I have an answer. In event driven programmer you have a publisher, a class that exposes the event) and at least one subscriber, a class that subscribes to your event through the use of a delegate. So, given that context your publisher raises an event, more than likely through some user interaction or user choice, and your subscriber makes a decision on what to execute based on what event was raised, thus the term event driven programming.


To demonstrate the use of delegates & events in C# we're going to create an alarm clock application that is driven by events from user interaction. In our alarm clock we will have 2 classes that inherit from System.EventArgs, which will hold the data for our events. We will have SetAlarmEventArgs and AlarmTriggerEventArgs and here's the code for them

using System;namespace DZoneArticles.EventsAndDelegatesExample{    public class SetAlarmEventArgs : EventArgs    {        public DateTime SetTime { get; set; }                public bool AlarmEnabled { get; set; }    }}using System;namespace DZoneArticles.EventsAndDelegatesExample{    public class AlarmTriggerEventArgs : EventArgs    {        public bool AlarmTurnedOff { get; set; }    }}

We will implement an interface based design into our example as well, we will name it IAlarmClock and it will handle the methods for working with the alarm clock that AlarmClock.cs will implement

using System;namespace DZoneArticles.EventsAndDelegatesExample{    public interface IAlarmClock    {        void AlarmClockSet(object sender, SetAlarmEventArgs e);        void AlarmTurnedOff(object sender, AlarmTriggerEventArgs e);        void TriggerAlarm(object sender, AlarmTriggerEventArgs e);    }}

In our AlarmClock.cs we will implement the above interface, and have properties that will be accessible in AlarmClockService.cs, which will do all the controlling of our alarm clock example

using System;namespace DZoneArticles.EventsAndDelegatesExample{    public class AlarmClock : IAlarmClock    {        public DateTime AlarmSetTime { get; set; }        public bool AlarmEnabled { get; set; }        public bool HitSnooze { get; set; }        public int SnoozeTime { get; set; }        public AlarmClock(DateTime setValue, bool enabled, bool snooze)        {            this.AlarmSetTime = setValue;            this.AlarmEnabled = enabled;            this.HitSnooze = snooze;        }        void IAlarmClock.AlarmClockSet(object sender, SetAlarmEventArgs e)        {            e.AlarmEnabled = this.AlarmEnabled;        }        void IAlarmClock.TriggerAlarm(object sender, AlarmTriggerEventArgs e)        {            //put your code here you want executed when the alarm is triggered\            e.AlarmTurnedOff = this.AlarmEnabled;        }        void IAlarmClock.AlarmTurnedOff(object sender, AlarmTriggerEventArgs e)        {            e.AlarmTurnedOff = true;        }    }}

Now for our alarm clock service. This is where all the events will be handled and triggered. We have two delegates and events derived from these delegates

public delegate void AlarmSetEventHandler(object sender, SetAlarmEventArgs e);public delegate void AlarmTriggerEvenHandler(object sender, AlarmTriggerEventArgs e);public event AlarmSetEventHandler AlarmSetEvent;public event AlarmTriggerEvenHandler AlarmTriggerEvent;

That will handle the meat of our event driven alarm clock example. We will ask the user for a value to set the alarm clock to, then monitor this with a timer in our client application. Once the proper date & time are reached we will call our TriggerAlarm method, which will then set out AlarmTriggerEvent. Once the user gives the command to turn the alarm off we will unregister the AlarmTriggerEvent to shut the alarm down, here's the code for our AlarmClockService.cs class

using System;namespace DZoneArticles.EventsAndDelegatesExample{    public class AlarmClockService    {        public delegate void AlarmSetEventHandler(object sender, SetAlarmEventArgs e);        public delegate void AlarmTriggerEvenHandler(object sender, AlarmTriggerEventArgs e);        public event AlarmSetEventHandler AlarmSetEvent;        public event AlarmTriggerEvenHandler AlarmTriggerEvent;        private AlarmClock clock { get; set; }        public bool IsAlarmTriggered { get; set; }        public bool IsAlarmEnabled { get; set; }        public AlarmClockService(AlarmClock c)        {            this.clock = c;        }        public void SetAlarm(DateTime setValue)        {            try            {                if (clock == null)                {                    throw new ArgumentException("An AlarmClock instance much be provided");                }                else                {                    if (DateTime.Compare(setValue.Date, System.DateTime.Now.Date) >= 0 && (!(TimeSpan.Parse(setValue.ToShortTimeString()) < System.DateTime.Now.TimeOfDay)))                    {                        if(this.IsAlarmTriggered)                            OnAlarmTimeSet(setValue);                    }                    else                    {                        throw new Exception("A date & time value before the current date & time isnt valid");                    }                }            }            catch (Exception ex)            {                Console.WriteLine(ex.Message);            }        }        protected void OnAlarmTimeSet(DateTime setValue)        {            if (AlarmSetEvent != null)            {                SetAlarmEventArgs args = new SetAlarmEventArgs();                args.SetTime = setValue;                args.AlarmEnabled = true;                AlarmSetEvent(this, args);            }        }        public void TriggerAlarm()        {            while ((clock.AlarmEnabled) && (!clock.HitSnooze))            {                OnAlarmTrigger();            }        }        protected void OnAlarmTrigger()        {            if (AlarmTriggerEvent != null)            {                AlarmTriggerEventArgs args = new AlarmTriggerEventArgs();                args.AlarmTurnedOff = false;                //code to play your alarm sound goes here                AlarmTriggerEvent(this, args);                            }        }        public void CancelAlarm(IAlarmClock iclock)        {            //make sure it's been cancelled            if (!this.IsAlarmEnabled)                this.AlarmTriggerEvent -= new AlarmTriggerEvenHandler(iclock.AlarmTurnedOff);            //code to stop playing the alarm sound        }        public void AttachSetEvent(IAlarmClock iclock)        {            this.AlarmSetEvent += new AlarmSetEventHandler(iclock.AlarmClockSet);        }        public void AttachTriggerEvent(IAlarmClock iclock)        {            this.AlarmTriggerEvent += new AlarmTriggerEvenHandler(iclock.TriggerAlarm);        }    }}

Now that we have the layout completed let's look at a quick implementation. We will need a timer class to monitor the time once the user sets the alarm. Since the actual timer control isnt available in a console application (which we are using for this example) we'll have to use the System.Threading.Timer class. First we need to create a callback method which matches the callback delegate (this will be used in the constructor of our timer control). In here we will set the value of a global DateTime variables being used to determine whether we trigger the alarm

private static void CheckTime(Object state){    nowValue = DateTime.Now;}

Then in main we ask the user for an alarm value, we then tick each second looking for the proper value and once we reach it we trigger the alarm. Once the alarm is triggered we give the user an option to turn the alarm off then act accordingly:

private static DateTime nowValue;static void Main(string[] args){    Console.WriteLine("Please provide a time for your alarm to go off");    DateTime setValue;    if (!DateTime.TryParse(Console.ReadLine(), out setValue))    {        Console.WriteLine("Invalid entry");    }    else    {        //create a new stock isntance        IAlarmClock c = new AlarmClock(setValue, true, false);        //provide our stock market instance know the stock        AlarmClockService service = new AlarmClockService((AlarmClock)c);        //attach events to the stock market, so it can notify the investor        //this uses the Observe pattern with delegates & events        service.AttachSetEvent(c);        service.AttachTriggerEvent(c);        //start the stock market        service.SetAlarm();        TimerCallback call = new TimerCallback(CheckTime);        //create a timer that ticks every second        Timer timer = new Timer(call, null, 0, 1000);        for (; ; )        {            if (nowValue == service.triggerValue)            {                service.TriggerAlarm();                break;            }        }        Console.WriteLine("Press C to cancel alarm");        if (Console.ReadLine().ToLower() == "c")        {            service.IsAlarmEnabled = false;            service.CancelAlarm(c);        }    }               Console.ReadKey();}

So that's how event driven programming works. I know this is a very simple example but I was trying to introduce you to the concept of event driven programming, and I know we could have made this more robust, such as snooze and such, but as stated this is just an example on how event driven programming works. I also want to admit that this implementation probably isnt the most efficient way to do it, and maybe in the future I'll have an addition to this article with a more improved, robust and efficient example on an alarm clock application with event driven programming. Thanks for reading :)

Event Event-driven programming csharp

Opinions expressed by DZone contributors are their own.

Related

  • Building Modern 3factor Apps in 2021 With Event-Driven Programming
  • Event Driven Architecture (EDA) - Optimizer or Complicator
  • Event-Driven Microservices: How Kafka and RabbitMQ Power Scalable Systems
  • Exploring Intercooler.js: Simplify AJAX With HTML Attributes

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!