Search Unity

Event call when a VisualElement is removed

Discussion in 'UI Toolkit' started by cecarlsen, Jun 26, 2019.

  1. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    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?
     
    R2-RT, dbdenny and AndrewKaninchen like this.
  2. SudoCat

    SudoCat

    Joined:
    Feb 19, 2013
    Posts:
    65
    By the looks of it, DetachFromPanelEvent should do what you want. It's fired when you remove an element from the hierarchy.
     
    cecarlsen likes this.
  3. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    Yep, that's the way to do it.
     
    cecarlsen likes this.
  4. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Amazing, it works.

    If it was named OnDestroyEvent or OnRemoveEvent I would probably have found it.
     
    Last edited: Jun 28, 2019
  5. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    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?
     
  6. antoine-unity

    antoine-unity

    Unity Technologies

    Joined:
    Sep 10, 2015
    Posts:
    780
    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.
     
    cecarlsen likes this.
  7. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    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.
     
    Last edited: Jul 25, 2019
  8. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    For future reference, I returned to this issue with fresh eyes to realize that I could just override the RemoveFromHierarchy method.

    Code (CSharp):
    1.  
    2. public new void RemoveFromHierarchy()
    3. {
    4.     base.RemoveFromHierarchy();
    5.     // Clean up stuff here and call RemoveFromHierarchy on children so that they can also clean up.
    6. }
    7.  
     
  9. uDamian

    uDamian

    Unity Technologies

    Joined:
    Dec 11, 2017
    Posts:
    1,231
    @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).
     
  10. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    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.
     
    BloodHound_PL likes this.
  11. danielaquestions

    danielaquestions

    Joined:
    Nov 4, 2021
    Posts:
    9
    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.
     
  12. R2-RT

    R2-RT

    Joined:
    May 8, 2019
    Posts:
    38
    @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` in `DetachFromPanelEvent`
    - Binding callback to `AttachToPanelEvent` that sets `isDetached = false`
    - Binding to timed callback (e.g `UnityEditor.EditorApplication.update`) in which you call desired piece of code if `isDetached == true`