Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net
Delegates in VB.Net Delegates in VB.Net
Delegates in VB.Net
Go Back  Xtreme Visual Basic Talk > > > > Delegates in VB.Net


Reply
 
Thread Tools Display Modes
  #1  
Old 04-11-2004, 10:22 AM
excaliber's Avatar
excaliberDelegates in VB.Net excaliber is offline
Senior Contributor

* Expert *
 
Join Date: Nov 2002
Location: Ohio, USA
Posts: 1,828
Default Delegates in VB.Net


Introduction
Here is a quick look at the usage of Delegates. Delegates are extremely powerful, but at first glance don't seem all that useful. Anyhow, a Delegate is a type-safe object oriented function pointer.

What's that mean
Well, lets look at the "function pointer" part first. Every function (or subroutine, or whatever) is really only an address in memory. To execute the function, you just move to the address and begin. A delegate object is just a "mobile" container for the memory address. Now the "type-safe" part. In C language there is a Callback method that provides a function pointer. But because the function pointer contains nothing more than the memory address, it does not have the argument list either. This means you can get some nasty results when trying to use a wrong set of arguments. VB.Net's delegate objects are type-safe though, meaning they will error you provide them the wrong set of arguments.

Simple example
Code:
Class Delegate 'This is the delegate declaration. Each delegate object must 'have a declaration. The Delegate keyword specifies it as a delegate 'declaration Public Delegate Sub delegateDog Private Sub Example() 'Here we create a delegate object by declaring as 'delegateDog (from the delegate declaration above) Dim doDog as delegateDog 'set the object to the AddressOf the Size subroutine doDog = AddressOf Size 'Invoke (or execute) the delegate (which really just executes 'the subroutine) doDog.Invoke() End Sub 'This is the target subroutine that will be used for the delegate Private Sub Size() MsgBox("Big dog") End Sub End Class
When run, a message box will appear with the words "Big Dog". Nifty. We declared a Delegate subrountine (delegateDog), then created an object as one. We set the delegate object to the AddressOf (returns the type-safe memory pointer) of the Size subroutine. Then we invoked the delegate

The cool thing about delegates is their OO properties. You treat them just like any other objects. They can be passed around from class to class, set to other delegates, etc. Very powerful stuff. Having a hard time seeing what's so great? Here are three examples.

The first is going to go without code, as it would require alot of explanation that is unrelated to delegates. In a typical multithreaded environment, any thread that tries to update the parent thread's UI will have trouble. Things start to get flaky when that happens. Instead of directly accessing the UI, or passing a reference to the form, you can pass a delegate. The delegate is set to the UI update function, then passed as an argument to the new thread. The thread can then update the UI whenever it chooses. Why can it do this? Because it's accessing the parent thread's function (and thus in the thread space of the parent), to update the UI (which is perfectly fine).

This is also codeless, because it is more of an explanation. Delegates can be used to give access to any function from any class. Say I have a private function in mySuperClass. I can create a delegate of that function and pass it to myClass. Normally, even if a reference of the class was passed, that function could not be accessed. But because you have a delegate of the fucntion, you can execute it from myClass (despite not having adequate "permission" to do so).

Last example, and this one has code. Ever wonder how Events work? An event just uses Delegates! VB.Net hides some stuff from you to make the interface nicer, but it's the same thing. Let's make a simple app that sets your bank balance (with a slider) and displays your "wealth rating".

First, the bank class:
Code:
Public Class clsBank 'An enum for making our lives easier Public Enum eWealth FilthyRich Rich Modest Poor LivingInBox End Enum 'the delegate declaration, this time it has an argument that may 'be passed as well. The argument is an eWealth Enum Public Delegate Sub BankEventHandler(ByVal WealthRating As eWealth) 'Now we declare the actual delegate object Private doWealthRating as BankEventHandler 'A variable to hold the actual wealth value Private intWealth as Int32 'This function allows the calling class to pass the delegate in initially. 'The delegate object will be passed to us from the calling class so that 'we can manipulate it Public Sub PassDelegate(ByVal doDel as BankEventHandler) doWealthRating = doDel End Sub 'Property that we will be using to show how events are the same as events Public Property WealthRating() As Int32 Get Return intWealth End Get 'If the value set is less than zero, set it to zero Set(ByVal Value As Int32) If Value < 0 Then intWealth = 0 Else 'Otherwise, set the internal wealth variable to the passed value intWealth = Value ' And here set up a select case on the value 'Each different case we invoke the delegate object and pass 'one of the Enum values. This is essentially executing the subroutine 'in the calling class. Select Case intWealth Case is > 100 doWealthRating.Invoke(CartridgeState.FilthyRich) Case 60 To 99 doWealthRating.Invoke(CartridgeState.Rich) Case 30 To 59 doWealthRating.Invoke(CartridgeState.Modest) Case 1 To 29 doWealthRating.Invoke(CartridgeState.Poor) Case is = 0 doWealthRating.Invoke(CartridgeState.LiveInBox) End Select End If End Set End Property End Class
We have alot going on in this code. First we have an Enum to make our lives easier later on. Then we have the declaration of the delegate subroutine, and then the actual object for the delegate. There is a subroutine to pass in the delegate from the calling class, and a property for the wealth rating.

And now the class to use the previous code:
Code:
Public Class Form1 'A new instance of the bank class from the previous code Private oWealth as New clsBank 'On the form load, we want to pass the AddressOf (the type 'safe function pointer) to the new class instance. This is so 'the bank class can manipulate the delegate object. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load oWealth.PassDelegate(AddressOf WealthStatus) End Sub 'Scrollbar event. Here we use the public property of the bank 'to set the value. Private Sub scrBankWealth_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles trInkLevel.Scroll oWealth.WealthRating = scrBankWealth.Value End Sub 'At the same time the scroller is moved, the delegate object in the other 'class will invoke this method (much like an event). It will also pass a 'BankEventHandler argument Private Sub WealthStatus(ByVal Status as clsBank.BankEventHandler) Dim Value as String 'A select case to display the value in a label Select Case Status Case clsBank.BankEventHandler.FilthyRich Value = "FilthyRich" Case clsBank.BankEventHandler.Rich Value = "Rich" Case clsBank.BankEventHandler.Modest Value = "Modest" Case clsBank.BankEventHandler.Poor Value = "Poor" Case clsBank.BankEventHandler.LiveInBox Value = "LiveInBox" End Select lblStatus = State End Sub End Class
Here, we have a new instance of the clsBank Class. On the load of the form, we pass a delegate to the class using AddressOf. Then there is the slider control's subroutine, which updates the class' wealth value. Then there is our delegate subroutine, WealthStatus, which displays the status in a label.

As you slide the slider, the label will change accordingly. Go back and look at the WealthRating property in clsBank. Notice how when it is set, it will invoke the delegate and pass an argument. Looking back at Form1, we see the delegate subroutine accepts the argument and deals with it by a select case and a label output.

Essentially, we just created a custom programmable Event and Event Handler. Pretty cool.

Conclusion
Delegate objects are extremely powerful, allowing you to access functions from anywhere in an object oriented manner. They can also be used to create custom events.
__________________
RandomIRC - Your neighborhood's friendly IRC channel (irc.randomirc.com - #code)

"Perl - The only language that looks the same before and after RSA encryption."

Last edited by excaliber; 04-11-2004 at 10:55 AM. Reason: Added Comments
Reply With Quote
  #2  
Old 09-11-2004, 05:06 AM
DeadalusDelegates in VB.Net Deadalus is offline
Promising Talent

Retired Moderator
* Guru *
 
Join Date: May 2002
Location: Brussels
Posts: 3,601
Default

Something seems to have gone wrong with that last example Excaliber gave, apparently it mixes up two different examples. He's not around, so I'm taking the liberty of attaching a working version of that example project. Any errors in this one are completely my merit.
Attached Files
File Type: zip Delegate_Simple.zip (6.2 KB, 301 views)
Reply With Quote
  #3  
Old 09-11-2004, 06:19 AM
DeadalusDelegates in VB.Net Deadalus is offline
Promising Talent

Retired Moderator
* Guru *
 
Join Date: May 2002
Location: Brussels
Posts: 3,601
Default Multicast delegates

An interesting feature about delegates is that they can be "multicast", which essentially means that they can notify or trigger multiple methods.

Take the last example above and suppose that we want that a change in wealthrating not only changes the label, but triggers another, seperate procedure as well (here a simple procedure that changes the form's background color, named WealthColor). The Load procedure of our form would look something like this:
Code:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'set the delegate to the first procedure oWealth.PassDelegate(AddressOf WealthStatus) 'set it to the second procedure (as well) oWealth.PassDelegate(AddressOf WealthColor) End Sub
With our current PassDelegate procedure this won't work. Or rather, it will, but the second line will simply replace the pointer to WealthStatus in our delegate with a pointer to WealthColor.

So we need to change the PassDelegate sub in such a way that it adds a function pointer to the one present rather than replacing it. Luckily, the Delegate class has a method Combine that lets us do just that.
Code:
Public Sub PassDelegate(ByVal doDel As BankEventHandler) doWealthRating = CType([Delegate].Combine(doWealthRating, doDel), BankEventHandler) End Sub
(Side note: Don't let the square brackets confuse you. They're just there to indicate that we mean the class Delegate, and not the identically named keyword. To avoid this trickery, we could also have done this:
Code:
doWealthRating = CType(doWealthRating.Combine(doWealthRating, doDel), BankEventHandler)
where we use a Delegate object to call the Shared method Combine. I prefer not to do that, to make clear it's not an instance method we're using.)

So what's happening here? We simply take two delegates, with their own list of functions they notify, and return a new delegate, with a notification list that combines these lists. The CType is only there because Combine returns a Delegate object and we want to store it in a variable of our more specific, derived delegate type.

So now when we use PassDelegate repeatedly, like in the Load sub above, we're adding methods to our notification list. When Invoke is called, all methods in this list will execute.

Note that when the first method is passed, doWealthrating will still be Nothing. Combine is defined to then return the other passed delegate, so we don't even need to code for this special case.

It's easy to see that in our simple example, we could have just elaborated the one existing method. Or, for that matter, used a classic event. It's equally clear though, that this gives us a very elegant way to add or remove logically independent procedures that should be triggered by the same event. Moreover, the methods that a delegate triggers can be in different classes, as long as they have access to the same delegate object.

A more elaborate discussion of multicast delegates can be found here: http://msdn.microsoft.com/msdnmag/is...asicInstincts/
Attached Files
File Type: zip Delegate_Multicast.zip (6.3 KB, 183 views)

Last edited by Deadalus; 09-11-2004 at 06:31 AM.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Passing variables and controls using WinForms and VB.NET Bucky Tutors' Corner 0 02-24-2004 04:45 PM
VB6 vs VB.NET geo1st487 Tech Discussions 10 01-31-2004 10:37 PM
Open VB.NET 2002 project within VB.NET 2003 geo1st487 .NET General 2 01-10-2004 05:13 PM
VB.Net Office Integration FAQ Mike Rosenblum .NET Office Automation 2 12-19-2003 01:17 PM
A VB6 to VB.NET conversion sample Helmar General 0 11-14-2001 06:27 PM

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net Delegates in VB.Net
Delegates in VB.Net
Delegates in VB.Net
 
Delegates in VB.Net
Delegates in VB.Net
 
-->