Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Caching VisualElements?

Discussion in 'UI Toolkit' started by VoodooDetective, Sep 16, 2022.

  1. VoodooDetective

    VoodooDetective

    Joined:
    Oct 11, 2019
    Posts:
    238
    I'm writing a contextual menu for runtime. I was just wondering if there's any benefit to caching VisualElements in an ObjectPool or if that's not particularly useful?

    Here's an example. This class will be for menu items within a context menu box:
    Code (CSharp):
    1. using System;
    2. using UnityEngine.Pool;
    3. using UnityEngine.UIElements;
    4.  
    5. namespace RUI
    6. {
    7.     public class RUIContextualMenuItem : VisualElement
    8.     {
    9.         private readonly static ObjectPool<RUIContextualMenuItem> s_Pool = new(Create, null, TearDown);
    10.         private readonly Label m_Label;
    11.         private readonly VisualElement m_Icon;
    12.         private Action m_OnClick;
    13.         private Action m_Close;
    14.         public string MenuText { get => m_Label.text; set => m_Label.text = value; }
    15.  
    16.         internal static RUIContextualMenuItem GetFromPool(MenuNode menuData, Action closeMenu)
    17.         {
    18.             // Get Item from Pool
    19.             RUIContextualMenuItem menuItem = s_Pool.Get();
    20.  
    21.             // Style
    22.             if (menuData.IsSeparator) // Separator
    23.             {
    24.                 menuItem.m_Label.style.display = DisplayStyle.None;
    25.                 menuItem.m_Icon.AddToClassList("contextual-menu-item-icon-separator");
    26.                 menuItem.SetEnabled(false); // No Hover
    27.             }
    28.             else
    29.             {
    30.                 // Set Name
    31.                 menuItem.MenuText = menuData.NodeName;
    32.  
    33.                 if (menuData.IsSubMenu) // Sub Menu
    34.                 {
    35.                     // Add Arrow Icon
    36.                     menuItem.m_Icon.AddToClassList("contextual-menu-item-icon-submenu");
    37.  
    38.                     // TODO
    39.                     UnityEngine.Debug.Log("Implement SubMenus");
    40.                 }
    41.                 else // Action
    42.                 {
    43.                     if (menuData.IsChecked)
    44.                     {
    45.                         menuItem.m_Icon.AddToClassList("contextual-menu-item-icon-checked");
    46.                     }
    47.                     if (menuData.IsDisabled)
    48.                     {
    49.                         menuItem.SetEnabled(false);
    50.                     }
    51.                     else
    52.                     {
    53.                         menuItem.m_OnClick = menuData.Execute;
    54.                         menuItem.m_Close = closeMenu;
    55.                     }
    56.                 }
    57.             }
    58.  
    59.             // Return Item
    60.             return menuItem;
    61.         }
    62.  
    63.         internal static void ReleaseToPool(RUIContextualMenuItem toRelease) => s_Pool.Release(toRelease);
    64.  
    65.         private static RUIContextualMenuItem Create() => new();
    66.         private static void TearDown(RUIContextualMenuItem toTearDown)
    67.         {
    68.             toTearDown.MenuText = string.Empty;
    69.             toTearDown.m_OnClick = null;
    70.             toTearDown.m_Close = null;
    71.             toTearDown.SetEnabled(true);
    72.             toTearDown.m_Label.style.display = DisplayStyle.Flex;
    73.             toTearDown.m_Icon.RemoveFromClassList("contextual-menu-item-icon-checked");
    74.             toTearDown.m_Icon.RemoveFromClassList("contextual-menu-item-icon-submenu");
    75.             toTearDown.m_Icon.RemoveFromClassList("contextual-menu-item-icon-separator");
    76.         }
    77.  
    78.         public RUIContextualMenuItem()
    79.         {
    80.             // Structure
    81.             m_Label = new Label();
    82.             m_Icon = new VisualElement();
    83.             Add(m_Label);
    84.             Add(m_Icon);
    85.  
    86.             // Style
    87.             AddToClassList("contextual-menu-item-container");
    88.             m_Label.AddToClassList("contextual-menu-item-label");
    89.             m_Icon.AddToClassList("contextual-menu-item-icon");
    90.  
    91.             // Register Click Callback
    92.             this.AddManipulator(new Clickable(OnClick));
    93.         }
    94.  
    95.         private void OnClick()
    96.         {
    97.             if (m_OnClick != null)
    98.             {
    99.                 m_OnClick();
    100.                 m_Close();
    101.             }
    102.         }
    103.     }
    104. }
    105.