In VB6, an event subroutine, like Button1_Click, was much less complicated because the system called the subroutine strictly by name. If a Button1_Click event existed, the system called it. It's direct and straightforward. But in VB.NET, there are two major upgrades that make VB.NET SOOPercharged. (That's "OOP" for Object Oriented Programming.)
- The "Handles" clause controls whether the system calls the subroutine, not the name.
- The sender and e parameters are passed to the subroutine.
Let's look at a simple example to see the difference that parameters make in VB.NET.
Private Sub Button1_Click( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles Button1.Click ' Your code goes here End Sub
Event subroutines always receive a "sender" object and a system EventArgs parameter "e". Because the EventArgs parameter is an object, it supports whatever properties and methods are necessary. For example, the old VB6 MouseMove event subroutine used to receive four parameters:
- Button As Integer
- Shift As Integer
- X As Single
- Y As Single
When more advanced mice came out with more buttons, VB6 had a real problem supporting them. VB.NET only passes one MouseEventArgs parameter but it supports a lot more properties and methods. And each of them are objects that support even more. For example, the e.Button property contains all these properties:
... and a whole list of methods. If someone invents a "trancendental" mouse with a "virtual" button, VB.NET will only have to update the .NET Framework to support it and no previous code will break as a result.
There are a number of .NET technologies that absolutely depend on these parameters. For example, since your PC usually only has a single screen to display graphics, your code has to merge the graphics it creates into the same image used by Windows. For that reason, a single "graphics" object has to be shared. The GDI+ (Windows graphics) tutorial, explains that the major way that your code is able to use that "graphics" object is to use the e parameter that is passed to the OnPaint event with the PaintEventArgs object. Here's an example:
Protected Overrides Sub OnPaint( ByVal e As System.Windows.Forms.PaintEventArgs) Dim g As Graphics = e.Graphics
What else can you do with these parameters? To illustrate, suppose you want to find whether a string, perhaps something you entered into a Textbox, exists in any one of a collection of other Textboxes when you click on one. You could code a few dozen virtually identical subroutines for each Textbox:
If TextBox42.Text.IndexOf( SearchString.Text) = -1 Then NotFound.Text = "Not Found"
But it's a lot easier to code just one and let it handle all of them. The sender parameter will reveal which Textbox was clicked.
Private Sub FindIt( ByVal sender As System.Object, ByVal e As System.EventArgs ) Handles TextBox1.Enter, TextBox2.Enter, . . . and on and on . . . TextBox42.Enter Dim myTextbox As TextBox myTextbox = sender Dim IndexChar As Integer = myTextbox.Text.IndexOf( SearchString.Text) If IndexChar = -1 Then _ NotFound.Text = "Not Found" _ Else _ NotFound.Text = "Found It!" End Sub
Recently, an About Visual Basic reader asked me for a better way to "delete the line that was clicked in any of six specified lists." He had it working in a couple of dozen lines of code that simply confused me. But using sender, it was really quite simple:
Private Sub ListBox_Click( ByVal sender As Object, ByVal e As System.EventArgs ) Handles ListBox1.Click, ListBox2.Click Dim myListBox As New ListBox myListBox = sender myListBox.Items.RemoveAt(myListBox.SelectedIndex) End Sub
One more example to nail down the point is a question that was sent in by Pierre in Belgium. Pierre was testing the equality of Button1 and sender using the Is operator for objects:
If sender Is Button1 Then ...
This is syntactically correct because sender and Button1 are both objects that can be referenced. And since sender really is identical with Button1, why doesn't it work?
The answer depends on a keyword that is found a little earlier in the statement. First let's check the Microsoft documenation for the Is operator.
Visual Basic compares two object reference variables with the Is Operator. This operator determines if two reference variables refer to the same object instance.
Notice that sender is passed ByVal. That means that a copy of Button1 is passed, not the actual object itself. So when Pierre tests to see if sender and Button1 are the same instance, the result is False.
To test whether Button1 or Button2 has been clicked, you have to turn sender into an actual Button object and then test a property of that object. Text is usually used, but you could test a value in Tag or even the Location property.
This code works:
Dim myButton As Button myButton = sender If myButton.Text = "Button1" Then