Click here to Skip to main content
15,881,757 members
Articles / Desktop Programming / WPF

Event Handler Made Simple

Rate me:
Please Sign up or sign in to vote.
4.87/5 (8 votes)
11 Mar 2016CPOL7 min read 17.8K   10   6
This article will explain what is needed for a custom event handler to work.

Introduction

First off no downloads, just simply create a new WPF (or Windows Forms) C# Application, copy code, paste code, run code. Styling is up to you. Where necessary, I will instruct you when to create an item (like a class library, form, etc.).

After poking around to try to explain event handlers in C#, I had a really hard time finding a truly simple example. Even when I found one that looked simple, I found the explanation around the code to be confusing. So I thought why not try to create this for myself and others.

Background

The best way to solidify your knowledge in something is to attempt to teach it!

This project has only 1 XAML or Windows Form (depending on what technology you prefer) and 1 class library. Typically, the single class library would be split into separate files for each different class, but that is not a necessity. In order to keep things as simple as possible, I have placed all of the event classes in one file.

Our custom "event" that we will create will contain two strings. One that will return a custom message to the interface, and another that will give us the status of the work. In this case, I will start with an event called WorkStart (made up name!). WorkStart will be triggered at the start of any work by our class library. The code behind the XAML (or Windows Form) will create a Worker object that we define in our class. Then, we will use the button click to tell that Worker Object to StartWork. The StartWork method in the Worker class will raise the event and the event will be handled in our form and the form textboxes will be updated.

Let's Code

Fire up Visual Studio. I am using version 2013, but 2015 will work as well. Older versions such as 2012 and even 2010 should work too. If you don't have Visual Studio, go out to Microsoft and get the Community version FREE!(provided you meet the licensing agreement). Next, create a new WPF (or Windows Form) application (using C#). You can name this anything you want, but I called mine "EventSimplified". After your project initializes itself, let's create a new class. Select the name of your project in the solution explorer and right click. Select Add, then at the bottom, Class. (Or you can just hit Shift + Alt + C). I named mine EventCode, but you can call yours anything you want. You will be presented with an empty class library:

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EventSimplified
{
    class EventCode
    {
    }
}

Ok, here is where your cut and paste skills come in handy! Copy the code below into your clipboard:

C#
// Delegate that handles the declaration in a class library as well as that in the User Interface
public delegate void WorkStartedEventHandler(object sender, WorkStartedEventArgs e);

//Class for specialized event handler
public class WorkStartedEventArgs : EventArgs
    {
        public string Status;
        public string Message;
        public WorkStartedEventArgs(string msg, string status)
        {
            Status = status;
            Message = msg;
        }
    }

//Class that will trigger the event (think of this as the event sender.  
//When something happens in here it triggers the event).
public class Worker
    {
        //Event declaration
	public  event WorkStartedEventHandler WorkStarted;
	
         //The class library method that triggers the event...
	 public void StartWork()
        {
                WorkStartedEventArgs WkStart = 
                new WorkStartedEventArgs("Awake!", "Starting Task!");
                OnWorkStart((object)this, WkStart);	
        }

        //The method that passes the event to the event handler
	void OnWorkStart(object o, WorkStartedEventArgs e)
        {
            if (WorkStarted != null)
                WorkStarted( o, e);
        }
    }

Now in your class library, highlight the class definition below the namespace. Make sure you get both curly braces.

C#
class EventCode
    {
    }

Paste in the code you copied. There, that wasn't so bad was it! Now before we actually get to putting in the XAML (not needed for Windows Forms) and the code behind, let's see what we just did.

The first line in the class library after the namespace now has this in there:

C#
// Delegate that handles the declaration in a class library as well as that in the User Interface
public delegate void WorkStartedEventHandler(object sender, WorkStartedEventArgs e);

What we did here is declare a delegate. A delegate essentially is a template for a method that will be called when your event fires. The important parts of the delegate are the parameters. The parameters define the signature for the event handler or in other words, what must be passed to the event handler.

The next part defines our WorkStartedEventArgs:

C#
//Class for specialized event handler
public class WorkStartedEventArgs : EventArgs
    {
        public string Status;
        public string Message;
        public WorkStartedEventArgs(string msg, string status)
        {
            Status = status;
            Message = msg;
        }
    }

This code creates a publicly available class. It inherits from the default EventArgs and adds two strings. When the WorkStartedEventArgs is created, it is passed two strings (our message and our status as we discussed above). By passing these two items in, we can set the value of the publicly available Status and Message properties of our WorkStartedEventArgs class.

The next section we pasted in is our Worker class. It is the class library that will perform our work for us.

C#
//Class that will trigger the event (think of this as the event sender.  
//When something happens in here it triggers the event).
public class Worker
    {
        //Event declaration
	public  event WorkStartedEventHandler WorkStarted;
	
         //The class library method that triggers the event...
	 public void StartWork()
        {
                WorkStartedEventArgs WkStart = 
                new WorkStartedEventArgs("Awake!", "Starting Task!");
                OnWorkStart((object)this, WkStart);	
        }

        //The method that passes the event to the event handler
	void OnWorkStart(object o, WorkStartedEventArgs e)
        {
            if (WorkStarted != null)
                WorkStarted( o, e);
        }
    }

First, we create the WorkStartedEventHandler and name it WorkStarted. We will be seeing this again in our UI where we will tie it to a form level method. The public void WorkStart section of the class is the method we will call from the code behind in the XAML form to start our work. The StartWork method creates a new WorkStartedEventArgs object and passes it two strings as we defined above. Then, we call the class level OnWorkStart method with the class object CAST into an object [(object) this] followed by the WorkStartedEventArgs object we created. We make sure that the WorkStarted event handler is not null, then call the event handler passing in the class object o and the WorkStartedEventArgs object e.

Now that we have all of our class library finished, let's get to work on the user interface and the code behind it.

XAML (WPF) People Go Here

XML
<Window x:Class="EventSimplified.MainWindow" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
</Grid>
</Window>

More cut and paste time... This is going to make a really ugly form. I apologize in advance, but it is functional and it does let you easily see the results. Copy the below code:

XML
<Window x:Class="EventSimplified.MainWindow"         
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
Title="MainWindow" Height="350" Width="525">    
<StackPanel>        
<TextBox Name="Status" Margin="10,10,0,0" />        
<TextBox Name="Message" Margin="10,10,0,0" />        
<Button Content="Button" Name="btnStart" 
Click="btnStart_Click" />     
</StackPanel>
</Window>

Select your entire XAML window and paste in the code you copied above. My apologies, it IS ugly! Note that if you named your application something different than EventSimplified, you will have to change this at the top line and out what you named your application in place of EventSimplified.

Open up the code behind the XAML page (while the cursor is in the XAML hit F7). Again, you can use cut and paste and simply paste in this code (Assuming you did not change the name of the MainWindow!) paste it AFTER the open brace of the namespace.

C#
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    //new instance of the worker class.
    Worker wk1 = new Worker();
    public MainWindow()
    {
        InitializeComponent();
        //Create the event handler for the form and assign it to wk1_started
        wk1.WorkStarted += new WorkStartedEventHandler(wk1_WorkStarted);
    }
    //Event Handler in the UI - This is what you want the UI to do When the event is triggered.

    void wk1_WorkStarted(object sender, WorkStartedEventArgs e)
    {
        //OK on the Form I have two Textboxes One Named Status, the Other Named Message
        Status.Text = e.Status;
        Message.Text = e.Message;
    }

    private void btnStart_Click(object sender, RoutedEventArgs e)
    {
        //Toggle the StartWork method in the class that will create the event args
        //and call the OnWorkStart method to toggle the event handler
        wk1.StartWork();
    }
}

Windows Forms People Go Here

For those of you using Windows Forms, you will now have to open up the default form.

Add two textboxes to it. Name one of them Status, the other name Message. Put a button on it and name it btnStart. Hit F7 to view code. Use your cut and paste skills to make the form look like the below form.

C#
public partial class Form1 : Form
    {
        //new instance of the worker class.
        Worker wk1 = new Worker();
        public Form1()
        {
            InitializeComponent();
            wk1.WorkStarted += new WorkStartedEventHandler(wk1_WorkStarted);
        }

        void wk1_WorkStarted(object sender, WorkStartedEventArgs e)
        {
            //OK on the Form I have two Textboxes One Named Status, the Other Named Message
            Status.Text = e.Status;
            Message.Text = e.Message;
        }
        
        private void btnStart_Click(object sender, EventArgs e)
        {
            //Toggle the StartWork method in the class that will create the event args 
            //and call the OnWorkStart method to toggle the event handler
            wk1.StartWork();
        }

WPF and Windows Forms Folks Unite and Read What Is Next!

Before we run this, let's look at what we did. The first line we added was to create a new Worker object. We defined this in our class library. That is this line:

C#
//new instance of the worker class.
        Worker wk1 = new Worker();

Then, after the Form initialization code (on BOTH XAML and Windows Forms!), we tied the Form's wk1_WorkStarted method to the WorkStarted event in the class. This is the plumbing that allows the class to raise the event on the form and tells the form what to call (shown below) when the event is raised. Notice that the parameters match the delegate we declared in the class library. It has to or it will not work!

C#
void wk1_WorkStarted(object sender, WorkStartedEventArgs e)
      {
          //OK on the Form I have two Textboxes One Named Status, the Other Named Message
          Status.Text = e.Status;
          Message.Text = e.Message;
      }

This is the code that you create to respond to the event. You can see how powerful this can be. Just let the imagination roam for a bit... OK, back at it, let's finish the discussion of the code. Finally, under the button click event, we put the code that starts the whole thing. When you run the code, the Worker class object (wk1) is created by the form, but nothing happens. That is because you need to click the button to start the work!

C#
//Toggle the StartWork method in the class that will create the event args
//and call the OnWorkStart method to toggle the event handler
wk1.StartWork();

OK, take a minute to run your code. Did it work? If not, check for Errors, correct and try again.

Now that we have a simple example, in the next segment, I will expand this to show a multithreaded example. Why multithreaded? Suppose the job you run in the class to do work takes a while (2-3 minutes or even longer). You want the user interface to remain responsive, update the user of the progress and not just turn white and give nothing but a wait cursor. The user might think your application has locked up and terminate it. The application has not locked up, but the thread that is running your user interface is the same one doing the work so it is busy and cannot update the interface. Multithreading allows you to run the user interface on one thread and other processes can run on other threads leaving you with a responsive interface that updates the user with the status of the long running process.

History

  • 3-11-2016 Submitted this first version!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionNice article! Pin
habe815-Mar-16 6:23
habe815-Mar-16 6:23 
AnswerRe: Nice article! Pin
patm300e16-Mar-16 1:43
professionalpatm300e16-Mar-16 1:43 
QuestionNice demonstration Pin
asiwel14-Mar-16 19:08
professionalasiwel14-Mar-16 19:08 
AnswerRe: Nice demonstration Pin
patm300e16-Mar-16 1:45
professionalpatm300e16-Mar-16 1:45 
QuestionClean code, good explanation. Thank you. Pin
colbrand12-Mar-16 8:34
colbrand12-Mar-16 8:34 
AnswerRe: Clean code, good explanation. Thank you. Pin
patm300e16-Mar-16 1:45
professionalpatm300e16-Mar-16 1:45 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.