Documentation

Unity Engine


User Manual

Script Reference

Unity Engine


UnbindView

Raised when a HierarchyView is about to be unbound from the HierarchyWindow. Typically used to cleanup resources associated with the view.
Read time 4 minutesLast updated 12 days ago

Definition

public static event HierarchyWindow.UnbindViewEventHandler UnbindView

Remarks

This event provides the same functionality as HierarchyNodeTypeHandler.OnUnbindView but at the window level for global cleanup.
The following example draws visual connector lines in the Hierarchy window to show the parent and child relationships between GameObjects. It uses
UnbindView
to clean up the per-view handler registered by
BindView
.
The example requires three USS files:
Connectors.uss
for the base styles,
Connectors_dark.uss
for the Dark theme, and
Connectors_light.uss
for the Light theme.
To use this example, save the script and USS files in a folder called
Assets/Editor/Connectors
. Scripts in an
Editor
folder can use the Hierarchy module API without additional setup. If you save the script outside of an
Editor
folder, you must enable the Hierarchy built-in module in the Package Manager window, which also adds the module to your Player builds.
using System; using System.Collections.Generic; using Unity.Hierarchy; using Unity.Hierarchy.Editor; using UnityEditor; using UnityEngine.Pool; using UnityEngine.UIElements; namespace Unity.HierarchySamples.Editor { class Connectors { const string k_ConnectorUssClassName = "connector"; const string k_ConnectorHoverUssClassName = "connector--hovered"; const string k_ConnectorContainerClassName = "connector-container"; [InitializeOnLoadMethod] static void Initialize() { HierarchyWindow.BindView += OnBindView; HierarchyWindow.UnbindView += OnUnbindView; } static void OnBindView(HierarchyWindow window, HierarchyView view) { view.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/Connectors/Connectors.uss")); view.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>($"Assets/Editor/Connectors/Connectors{(EditorGUIUtility.isProSkin ? "_dark" : "_light")}.uss")); ConnectorsHandler connectorHandler = new ConnectorsHandler(view); view.BindViewItem += connectorHandler.OnBindViewItem; view.userData = connectorHandler; } static void OnUnbindView(HierarchyWindow window, HierarchyView view) { if (view.userData is ConnectorsHandler connectorHandler) view.BindViewItem -= connectorHandler.OnBindViewItem; } class ConnectorsHandler { static readonly List<VisualElement> s_ConnectorsCache = new(); static readonly ObjectPool<VisualElement> s_ConnectorVisualElementPool = new(() => new VisualElement(), actionOnRelease: e => e.userData = null); readonly HierarchyView m_View; int m_HoverDepth = -1; internal ConnectorsHandler(HierarchyView view) => m_View = view; internal void OnBindViewItem(HierarchyView view, HierarchyViewItem viewItem) { HierarchyViewModel viewModel = view.ViewModel; VisualElement connectorContainer = viewItem.Q(className: k_ConnectorContainerClassName); if (connectorContainer == null) { connectorContainer = new VisualElement(); connectorContainer.AddToClassList(k_ConnectorContainerClassName); viewItem.Add(connectorContainer); } s_ConnectorsCache.Clear(); connectorContainer.Query(className: k_ConnectorUssClassName).ToList(s_ConnectorsCache); // Depth is 0 when filtering because the tree is flattened int nodeDepth = view.Filtering ? 0 : viewModel.GetDepth(viewItem.Node); HierarchyNode nodeParent = viewModel.GetParent(viewItem.Node); bool parentHasHoveredFlag = viewModel.HasFlags(nodeParent, (HierarchyNodeFlags)HierarchyNodeFlagsExtended.ConnectorsHovered); for (int i = 0; i < nodeDepth; i++) { VisualElement connector; if (i < s_ConnectorsCache.Count) { connector = s_ConnectorsCache[i]; } else { connector = s_ConnectorVisualElementPool.Get(); connector.AddToClassList(k_ConnectorUssClassName); connectorContainer.Add(connector); connector.RegisterCallback<MouseEnterEvent>(OnMouseEnter); connector.RegisterCallback<MouseLeaveEvent>(OnMouseLeave); connector.RegisterCallback<MouseDownEvent>(OnConnectorPressed); } connector.userData = (viewItem, i); connector.style.left = i * 14; connector.EnableInClassList(k_ConnectorHoverUssClassName, parentHasHoveredFlag && i == m_HoverDepth); } for (int i = nodeDepth; i < s_ConnectorsCache.Count; i++) { VisualElement connector = s_ConnectorsCache[i]; connector.RemoveFromHierarchy(); connector.UnregisterCallback<MouseEnterEvent>(OnMouseEnter); connector.UnregisterCallback<MouseLeaveEvent>(OnMouseLeave); connector.UnregisterCallback<MouseDownEvent>(OnConnectorPressed); s_ConnectorVisualElementPool.Release(connector); } } static (HierarchyViewItem viewItem, int depth) GetConnectorData(EventBase evt) => ((HierarchyViewItem, int))((VisualElement)evt.currentTarget).userData; void OnMouseEnter(MouseEnterEvent evt) { (HierarchyViewItem viewItem, int depth) = GetConnectorData(evt); m_HoverDepth = depth; HierarchyNode ancestor = GetAncestorAtDepth(viewItem, depth); viewItem.View.ViewModel.SetFlagsRecursive(ancestor, (HierarchyNodeFlags)HierarchyNodeFlagsExtended.ConnectorsHovered, HierarchyTraversalDirection.Children); } void OnMouseLeave(MouseLeaveEvent evt) { m_HoverDepth = -1; m_View.ViewModel.ClearFlags((HierarchyNodeFlags)HierarchyNodeFlagsExtended.ConnectorsHovered); } void OnConnectorPressed(MouseDownEvent evt) { (HierarchyViewItem viewItem, int depth) = GetConnectorData(evt); HierarchyNode ancestor = GetAncestorAtDepth(viewItem, depth); if (evt.altKey) viewItem.View.ViewModel.ClearFlagsRecursive(ancestor, HierarchyNodeFlags.Expanded, HierarchyTraversalDirection.Children); else viewItem.View.ViewModel.ClearFlags(ancestor, HierarchyNodeFlags.Expanded); } HierarchyNode GetAncestorAtDepth(HierarchyViewItem viewItem, int depth) { HierarchyNode ancestor = viewItem.Node; for (int i = viewItem.View.ViewModel.GetDepth(viewItem.Node); i > depth; i--) ancestor = viewItem.View.ViewModel.GetParent(ancestor); return ancestor; } } // Custom flags can be defined by using unused bits in the HierarchyNodeFlags enum. // This example uses bit 4 to track hover state for connector visualization. enum HierarchyNodeFlagsExtended : uint { ConnectorsHovered = 1 << 4 } } }
The following example shows how to style
Connectors.uss
.
.connector { width: 10px; border-left-width: 1px; height: 100%; position: absolute; } .connector-container { position: absolute; left: 12px; top: 0; background-color: chartreuse; height: 20px; width: auto; } .connector.connector--hovered{ border-left-width: 1px; }
The following example shows how to style
Connectors_dark.uss
.
.connector { border-left-color: rgba(169, 169, 169, 0.42); } .connector.connector--hovered{ border-left-color: darkgrey; }
The following example shows how to style
Connectors_light.uss
.
.connector { border-left-color: darkgrey; } .connector.connector--hovered{ border-left-color: grey; }