# UnbindView

> Raised when a HierarchyView is about to be unbound from the HierarchyWindow. Typically used to cleanup resources associated with the view.

## Definition

* **Type:** Event
* **Namespace:** [Unity.Hierarchy.Editor](/engine/6000.7/script-reference/unity/hierarchy/editor.md)
* **Assembly:** UnityEditor

```csharp
public static event HierarchyWindow.UnbindViewEventHandler UnbindView
```

### Remarks

This event provides the same functionality as [HierarchyNodeTypeHandler.OnUnbindView](/engine/6000.7/script-reference/unity/hierarchy/hierarchynodetypehandler/onunbindview.md) 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.

```csharp
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`.

```csharp
.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`.

```csharp
.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`.

```csharp
.connector {
 border-left-color: darkgrey;
}

.connector.connector--hovered{
 border-left-color: grey;
}
```
