Event handler that works intermittently

I have a window that is opened to perform a task. The task is run from a timer, and when complete it raises an event, then hides itself (does not close, just hide). App has attached a handler to the event, and it gets information from the window via a method.

The problem is, the event handler is run “some of the time”. So I am not sure whether I’m setting up the handler wrong, there is a bug in xojo, or perhaps something i am doing is corrupting memory.

One thought I have, is whether closing the window would require that the handler be attached again? That is, if there is a window in my application, and without opening it, I attached a handler to it’s event, can I expect this to work when the window is opened?

Any ideas?

TIA

No need for AddHandler. The proper way to do this is – in my opinion – is to have a public method in App, which you call from the window’s Hide event.

By the way: each AddHandler needs a corresponding RemoveHandler.

The problem with “calling up” like that, is that it creates coupling between the two parts of the program. App and window now need each other, to compile. Using an event, window does not need to know about app. App still knows about window…window is it’s “junior executive” you might say.

Coupling like that eventually forms a mass where no part of the program can be separated from the other parts. So it works against reusable code. For instance, my window performs discovery (finds out what hardware is attached). I might want to write 3 different programs that all use that functionality.

I have never used removeHandler. I don’t know why that would be needed, if the handler was in use for the lifetime of the program.

This is tight coupling too, just the other way around.

I guess you are right…because the App now has the AddHandler instruction which couples it to the window. But I am treating the App object as the integrator. It is the part of the program that integrates the other parts. It knows about all the parts already, that is its job.

The approach to design that I find is most workable is hierarchical. By following the rule of never calling up the hierarchy, I find that makes my programs very easy to understand. No spaghetti results.

I suppose one could follow an opposite rule and it would work just as well. Just following a rule simplifies the code.

Another approach to reducing coupling is the use of interfaces, which I think is pretty much Standard Operating Procedure for OOP. I think that is a good idea, though a partial solution and adds some complexity in that it adds another piece. I could for instance have the window call into an interface which the app implements. But I still need to carry around that interface with the window. The interface is lightweight, it has no real liabilities that come with it (ie other connections to objects that turn the code into one mass).

For now, I am not unhappy with the event approach. I just want to know why it doesn’t work reliably! If no one can answer that question, then I may need to follow your advice.

Using events it works without problems:

[code]Class App Inherits Application

Sub Open()
AddHandler Window1.Hide, AddressOf Window_Hide
End Sub

Function CreateWindow() As Boolean // This is the menu handler for a menu item called CreateWindow
Dim win As New Window1()
Return True
End Function

Sub Window_Hide(win As Window)
RemoveHandler Window1(win).Hide, AddressOf Window_Hide
// Get all the info you need from the window
win.Close()
End Sub

End Class[/code]

[code]Window1 Inherits Window

Event Hide()

Function MouseDown(X As Integer, Y As Integer) As Boolean
RaiseEvent Hide()
Self.Hide()
End Function

End Class[/code]

Integrator <> decoupling. This doesn’t mean you architecture is bad. But decoupling is something else than what you describe.

I’m not saying the integrating component = decoupling. I am saying that is a design decision, already made and acceptable to me, so I am not worried about coupling with that component.

I think I will try your code. That is, actually remove the handler, and close the window, and reconstruct the whole thing each time. It seems like more work than should be necessary, but if that’s what it takes to make it work, so be it.

Thanks for your help!

BTW, this is the code, based on yours, and it works :

Private Sub cmd_discover(what As String)

DiscoverWnd.Show
AddHandler DiscoverWnd.Complete,AddressOf evt_discover_complete
DiscoverWnd.Start what

End Sub

Sub evt_discover_complete(wnd As DiscoverWnd,what As String)

//*** discovery complete: act on the data discovered here

RemoveHandler DiscoverWnd.Complete,AddressOf evt_discover_complete
DiscoverWnd.Close

End Sub

Actually my code has a mistake. In my little test project I didn’t turn off “Implicit Instance” on Window1. And got no error therefore.

Correct version:

[code]Sub Open()
// no code here
End Sub

Function CreateWindow() As Boolean // This is the menu handler for a menu item called CreateWindow
Dim win As New Window1()
AddHandler win.Hide, AddressOf Window_Hide
Return True
End Function[/code]

???

Addhandler when used with AddressOf creates a reference to the object that owns the handler method (App in your case) that is held by the object whose event is being handled (the window). Since objects in Xojo are refcounted, you must use RemoveHandler to properly decrement the refcount for the handler object (App). Your specific case is a little special since the App instance exists for the duration of the program anyway.

Additionally, if the object whose event is being handled (window) is a property of the handler object (App) then using AddressOf creates a circular reference that prevents the refcount on both objects from reaching zero until the handler is removed. This can be intentional, but more often than not this is a bug.

In such cases it may be preferable to use WEAKAddressOf to assign event handlers. WeakAddressOf does the same thing as AddressOf but without creating a reference (c.f. WeakRef class.) Event handlers assigned using WeakAddressOf do not need to be explicitly removed.

Deciding when and how to use AddressOf vs WeakAddressOf is based on how you want the objects to be destroyed.

I have a similar issue: I have a handler that sends a message to a web viewer, that is either invoked by a method triggered by a timer or a method triggered by a message received by a socket; both methods are members of the same class.

The timer-triggered methods behaves well; data is formatted and sent. The socket-triggered method sends, as a test, the same message (which should trigger the event handler) but is ignored.

Any pointers as to how to go about debugging this?

As an additional datapoint, I called the successful timer-based method from within the unsuccessful socket-based one, and the event no longer triggered its handler - thus it appears it had been disabled. How can this happen?

Is this on macOS or Windows?

I would check the following:

  • put in code to see if your events or methods are operating inside a thread:
  if app.currentThread <> nil then
    system.DebugLog (currentMethodName + " is THREADED")
  end if

Some things (such as sending messages to a webViewer may fail inside a thread).

  • watch Console.log: I’ve seen cases where a NSException can be thrown inside Cocoa code and the result is that it exits a function or method (or event) silently and prematurely. Very hard to debug.

  • as mentioned above, watch for confusion of windows with ImplicitInstance=true, as this can cause much confusion.