Child->Grandparent Object Communication

I have a container control that acts like a listbox where each row is a container control. I want an arbitrary row to be able to enter an edit mode, and then have that row signal back to the listbox that it has exited edit mode (for example it’s save/close/cancel button was clicked). I have everything working well from the listbox side - telling a row to enter edit mode, telling a row to exit edit mode if another row was selected, etc.

What I am not sure about is the best way to have the row tell the listbox it has exited edit mode. The listbox keeps track of which row is in edit mode and the row would need to tell the listbox that it was done. I don’t see any way to do this without the row keeping a reference to the listbox, but I was hoping there was a more generic way. I would like the row container control to not need any specific properties, although an interface implementation would be OK.

The object hierarchy is container control (listbox) -> canvas -> container control (row), but the listbox container control maintains an array of the row container controls.

In the Listbox add a event definition “EditingFinished” with properties if required. In your code for the editing add a

RaiseEvent EditingFinished

Now go to the parent container and select the instance of the child container. Now add an event. The EditingFinished event should be available. Now you can communicate from child to parent.

Define an event on the row (RowFinishedEditing) that the listbox then implements.

This should allow the listbox to receive messages from the rows.

Have a look at delegates.
If you’re creating rows on the fly, I think that would be the way to go.

@Beatrix Willius and @Kevin Gale - My description might not have been clear enough. The Child/Grandparent relationship is not class/subclass, but nesting (row.parent.parent = listbox). Unless I am missing something, RaiseEvent cannot be called from outside the class, right?

@jim mckay - I am creating and destroying the rows on the fly. I think delegates are the solution. I say think because I’ve never used them before and my mind is mostly, but not completely, wrapped around the concept at the moment.

If I were to use delegates, the delegate would be declared in the listbox class, right? And be invoked from the row?

Nope, this will work fine. I use this all the time for communication. Delegates are good for something that you create at runtime. The rows are part of the listbox and are not a separate class.

I think i’m getting it now…

-The delegate is declared in the listbox
-When a row is created it stores a reference to the delegate in a property
-When a row exits edit mode it invokes the delegate reference

But… Since the row would need to have a property to store the delegate reference and then it would have to invoke that reference, I don’t see any real difference from the row having a property to store the listbox reference and calling a method from that.

My goal was to let the row container controls be as generic as possible (i.e. - just drop in any container control you want without having to require any specific properties be added to the row). I guess that’s not possible since row-to-listbox communication needs some kind of reference to the listbox on the row side. Oh well, it’s not a deal breaker…

@Beatrix Willius - my “listbox” isn’t a real listbox, it’s a container control with a canvas and two scrollbars, and the “rows” are container controls embedded within the canvas.

I’d still go with events for communication from the row to the outside world. Use AddHandler to tie the event to a method at runtime. It’s a specific kind of delegate that is called for you when the event is raised. Define a Class Interface that all the row containers implement, so you have a common api for communication from the outside into the container.

Would this not work?

In your ListThing class, create a method RowDoneEditing, to which is passed the number of the Row that’s exiting edit mode.
In your Row class, when done editing, call ListThing(Parent).RowDoneEditing(me.RowNum).

@Tim Hare - I was thinking about a Class Interface. I will probably implement that.

@Julia Truchsess - That is basically what I have settled on.

Thank you everyone for your advice and time. I appreciate it.