I am extending VisualElement and need to know when the element is removed from the hierarchy, so that I can automatically remove associated objects. But how?
By the looks of it, DetachFromPanelEvent should do what you want. It’s fired when you remove an element from the hierarchy.
Yep, that’s the way to do it.
Amazing, it works.
If it was named OnDestroyEvent or OnRemoveEvent I would probably have found it.
Thanks @uDamian
It seems that the event is not only fired when an element being deleted, but also when the panel window it lives inside is being detached and and reinserted in the Unity Editor, in which case the element is not actually removed. Perhaps it is being deleted and then recreated in the background, who knows.
I need to know when the element is being removed for good. Is there any way to check for that?
Somewhat related to the other thread, there is no way to distinguish between those scenarios unfortunately.
What kind of clean-up do you actually want to perform ? There might be several options like using a finalizer, using the dispose pattern or relying on the EditorWindow.OnDestroy() callback to deal with the whole window being removed.
Thanks @antoine-unity this was helpful.
The specific case is a ConnectionElement that needs to call DetatchFromPorts on it’s two related PortElements that removes references to it, but only when it is destroyed, not when the window is docked.
I ended up calling target.RemoveFromHierarchy() when receiving the DetachFromPanelEvent in an ConnectionElement to make sure that the behavior is consistent when the event is fired (so that it will always mean the element is removed). Then I just check for change and regenerate the connections in window OnFocus.
For future reference, I returned to this issue with fresh eyes to realize that I could just override the RemoveFromHierarchy method.
public new void RemoveFromHierarchy()
{
base.RemoveFromHierarchy();
// Clean up stuff here and call RemoveFromHierarchy on children so that they can also clean up.
}
@cecarlsen Note that “RemoveFromHierarchy()” is not the only way an element can change panels. If you set its “parent” property to null or a different parent, it will also be remove/added to a panel. Also, “RemoveFromHierarchy()” is not virtual so your override might not be called by others when calling this member function.
The removal of ports should really be done by the deleter of your node, not by the node itself. The Detach/Attach events are best used when they are symmetric (you always do the same setup/teardown for any/all Detach/Attach events, even Window docking).
Thanks @uDamian , you are right, overriding RemoveFromHierarchy with ‘new’ is far from optimal. If VisualElement had a OnDestroy method I would prefer to handle associated cleanup there. Then the patch would never break no matter how (or by who) the node is deleted. But since that is not the case, I will let the deleter do the work as you suggest.
Is there any other alternative to know when a Visual Element is removed? The “DetachFromPanelEvent” doesn’t quite do what I’m after as I’m wanting to run a piece of code when a VisualElement is actually gone from the hierarchy for good.
@danielaquestions The only way I’ve found is to detect DetachFromPanelEvent
without AttachToPanelEvent
right after it. So you could detect that element is unattached by:
- Setting some flag
bool isDetached = true
inDetachFromPanelEvent
- Binding callback to
AttachToPanelEvent
that setsisDetached = false
- Binding to timed callback (e.g
UnityEditor.EditorApplication.update
) in which you call desired piece of code ifisDetached == true