Interface with AddHandler

Some weeks ago I played around with a project to make a listbox of containers. I now want to add different containers to the listbox.

This is the code to add a container:

Public Sub AddItem(theContainer as ContainerControl)
  theContainer.EmbedWithin(Self, 0, InsertOffset, Self.Width, theContainer.Height)
  
  If theContainer IsA ItemContainerControl Then
    Dim ICC As ItemContainerControl = ItemContainerControl(theContainer)
    AddHandler ICC.RemoveMe, AddressOf ItemClickedRemove
  End If
  
  items.Append(theContainer)
  theContainer.TabIndex = items.LastIndex
  InsertOffset = InsertOffset + theContainer.Height
  
  // resize container to fit new one
  Self.Height = Max(Self.Height, InsertOffset)
 
End Sub

The reference to ItemContainerControl needs to be changed to an interface. I think that I need to use a delegate. But from examples and the docs I can’t work out what delegates are let alone use them.

Project:
ContainerControl List.xojo_xml_project.zip (8.6 KB)

I think it’s a fancy way of describing having a variable that contains a method address (which you can therefore alter at runtime), in order to have a set of methods and can decide at runtime which to call. I think.

So, in Pseudo-Xojo, one might imagine having:

Var  myPtr as Method, methods(2) as method

methods(0) = AddressOf Method1
methods(1) = AddressOf Method2
//  etc

myPtr = methods (i)   // i caluculated according to some criterion, at runtime
Call myPtr (args, ...)

You could use a non-UI ContainerControl in the class hierarchy to have an “interface” with an event definition.

Class RowContainer Inherits ContainerControl
  #Event Definition RemoveMe

Class RowTypeOne Inherits RowContainer
Class RowTypeTwo Inherits RowContainer

@TimStreater : what is the difference to a simple AddHandler?

@Tim_Parnell : thanks! That works.

ContainerControl List.xojo_binary_project.zip (13.9 KB)

Delegates can be used, as Tim mentioned, to vector any code programmatically at runtime e.g.

`MyMethods(AnIndex).Invoke // MyMethods is an array of Delegates

or

MyDelegate(MyMethods.Value(SomeKey)).Invoke // MyMethods is a Dictionary

MyDelegate has been declared as a Delegate somewhere in scope.

I know that theoretically. But I don’t have any idea how to use this in my situation (even though the problem is solved).

OK, cool. From your comment

and question

I thought you were seeking some enlightenment :slight_smile:

Delegates aren’t actually that hard to use once you understand them. The problem is, this use case is far better suited for an Event Definition / Handler, so it’s not a great example for me to describe delegates with.

The elevator pitch for how to use Delegates might be something like this:

The Delegate definition should be the signature of the eventual target function but the name doesn’t matter (parameters and return type do!). Store an address that handles the Delegate (has the same signature, name not important) as the value for a property or variable defined as MyDelegate.

Any time you want to call the function you defined the address of, check the Delegate property isn’t nil, and then use the Invoke function as if it were the function you intend to call.

In pseudo-code:

var oHandler as MyDelegate = WeakAddressOf SomeFunction

if oHandler <> nil then
  var bReturn as Boolean = oHandler.Invoke(sSomeParameter)

end
Private Function SomeFunction(sParatmeter as String) as Boolean

So, to add a delegate to a Module, I’d go RightMouse → Add Delegate and there I can define the delegate’s parameters and return value. Its name too - using your example that would be MyDelegate.

This appears to define a type, essentially, which I can use to declare a variable in the usual way, and so to adapt my example of upthread, this becomes:

Var  myPtr as MyDelegate, methods(2) as MyDelegate

methods(0) = AddressOf Method1
methods(1) = AddressOf Method2
//  etc

myPtr = methods(i)
myPtr.Invoke (same parameters here)

Method1 and Method2 are just ordinary methods whose signatures must match that of the delegate declaration.

In fact I use this approach so that I can have a method for reading from a socket, another for reading from a textinputstream, and have the same code using either.

1 Like

Thanks for the explanations. Still not sure why and where I need this. I can have a method from a socket and reading from an inputstream with the same name far easier with an interface and a factory.

You may not :slight_smile: One use case example:

I once wrote an app for testing a line of audio products. It had a whole bunch of test methods, each for one parameter of the product: frequency response, gain, distortion, power consumption, etc. The particular tests to be performed and the order in which they were to be performed could vary depending on the product and wasn’t 100% known at design time, so flexibility was required.

The test sequence was controlled by text (XML) files, which could be loaded at runtime. Each “test spec” file contained among other things a list of the names of the tests to be performed and their order of performance. The app would iterate over this list, looking up and invoking delegates pointing to the test methods from a dictionary whose keys were the test names.

This decoupled the test procedures from the code and made it easy to have different procedures for different products or to make changes without having to recompile and re-deploy the app.