User Rating: 4 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Inactive
 

If you create PowerShell GUI apps in PowerShell Studio, you become very familiar with the events of the Windows Forms types, like the Load event of forms, the Click event of buttons, and the TextChanged event of textboxes.

PowerShell Studio handles most of the background details of event management for you, but it’s useful and interesting to understand how events work in the Microsoft .NET Framework. This knowledge comes in especially handy when something doesn’t work and you need to understand enough to fix it.

One of the little mysteries that I couldn’t understand were the methods the .NET uses to register events, so I was delighted when PowerShell MVP Keith Hill wrote a great deep-dive blog post, An Explanation of the .NET add_EventName / remove_EventName Methods for PowerShell Scripters, that explains how it works.

Among other things, Keith explains that, for every event that is defined in a class, the C# compiler dynamically creates a method that registers event handlers for that event.

If you’re not a developer or a scripter with a strong development background, Keith’s post might be a bit advanced, so I thought I’d set it up for you.

Events and Event Handlers

An event is a member of a class, just like a property or a method. When you use the Get-Member cmdlet, by default, it returns events, along with the other member types.

For example, a close button ($buttonClose) is an instance of the button class, System.Windows.Forms.Button. You can create a button and add it to a form.

    #Create a close button 
    $buttonClose = New-Object 'System.Windows.Forms.Button'
 
    #Add it to the form. Use the Add method of the form's Controls property. 
    $form1.Controls.Add($buttonClose)

Like all buttons, in fact, like all controls, $ButtonClose has a Click event. When the Click event happens (“is raised”), the system calls the event handler for the Click event.

PS C:\> $buttonClose | Get-Member –Name Click

    TypeName: System.Windows.Forms.Button

Name  MemberType Definition

----  ---------- ----------

Click Event      System.EventHandler Click(System.Object, System.EventArgs)

An event handler is code or script that is designed to respond to an event.

Typically, you write the event handler commands in a script block and save them in a variable that is named for the event.

In this example, we write an event handler for the Click event of $buttonClose. We write a command that calls the Close() method of the form, enclose it in a script block, and assign it to a variable conveniently named $buttonClose_Click.

Despite its usefulness, the variable name is just a name and it has no effect on the outcome.

#Create an event handler
$buttonClose_Click = { $form1.Close() }

 

Register the Event Handler

The next step is to “register” the event handler script. Registering associates the Click event with the $buttonClose_Click event handler. When the event handler is registered, the system runs the commands in the event handler whenever the Click event happens on the $buttonClose button.

To register an event handler in PowerShell Studio, in the Properties box, click the Event icon (thunderbolt). In the row for the event, such as Click, type the name of the event handler variable without the dollar sign ($).

For the default event of each type, like the Click event of a button, PowerShell Studio does it for you.

Properties>

But, in the background, PowerShell Studio writes a command to register the event handler.

Here’s the syntax of an event registration command.

.add_($eventHandler)

For example:

#Register an event handler for the Click event
$buttonClose.add_Click($buttonClose_Click)

In this case, $buttonClose is the object, $buttonClose_Click is the event handler.

But what is add_Click()? Or, more generally what are those methods named add_<EventName>? If you search MSDN in the Button class (System.Windows.Forms.Button), or the class of any other control, or even their parent classes, you won’t find any methods named add_Click() or add_<AnyEventName>.

That’s what Keith explains in his post.

Keith Hill’s Excellent Blog Post

Keith begins his blog post by explaining that when you write a class and add a property, like Name, the language lets you write code to get the current value of the property and change (set) it. The code that you use to get and set property values is “syntactic sugar,” that is, it’s a shortcut for more complex code that’s written in the background.

The programmer writes C#. Then, the compiler takes the C# as input, interprets it, and returns an .exe or .dll file of code in Common Intermediate Language (CIL). CIL is general stuff – not hardware specific. Later, right before you run the code or “just in time,” another tool converts the CIL to hardware-specific code that the machine can run.

Thus, for every property that you add to a class that the user can get and set (change), like the Name property, the compiler creates two methods, get_<propertyName>() and set_<propertyName>(), such as get_Name() and set_Name(), to do the deeds.

Similarly, for every event that you add to a class, like the Click event of a button, the compiler adds a method to register the event. The name of the registration method is add_<EventName>.

Bingo! Now we know that the method that registers an event handler for a Click event is always called add_Click(), just like the method that registers an event handler for the TextChanged event is called add_TextChanged().

And, we know that we have the C# compiler to thank for this convenience.

We also understand why there’s no documentation of these dynamically created methods in the MSDN reference for the class. It’s because these methods aren’t defined as part of the class. They’re added automatically after the class is defined. (It still would be nice to have a line or two of explanation.)

But, it’s great to have another piece of the mystery solved. Now, when I use the Deploy / Export to Clipboard or Export to File commands in PowerShell Studio and examine the .ps1 file that PowerShell Studio generates, I understand how it registers the event handlers I write.

June Blender is a technology evangelist at SAPIEN Technologies, Inc. You can reach her at This email address is being protected from spambots. You need JavaScript enabled to view it. or follow her on Twitter at @juneb_get_help.

If you have questions about our products, please post in our support forum.
For licensed customers, use the forum associated with your product in our Product Support Forums for Registered Customers.
For users of trial versions, please post in our Former and Future Customers - Questions forum.
Copyright © 2024 SAPIEN Technologies, Inc.