Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Join us on Thursday, June 8, for a Q&A with Unity's Content Pipeline group here on the forum, and on the Unity Discord, and discuss topics around Content Build, Import Workflows, Asset Database, and Addressables!
    Dismiss Notice

Question How to identify which element was clicked?

Discussion in 'UI Toolkit' started by Kazko, Jan 15, 2021.

  1. Kazko

    Kazko

    Joined:
    Apr 2, 2014
    Posts:
    82
    I am trying to create a dynamic list of options for runtime menu, but have trouble identifying which of the options was clicked ...

    First I instantiate multiple items and .Add(item) them to some parent VisualElement ...
    then I customize the items (for example change label/icon) ...
    then I register a ClickEvent callback method to each of those items ...

    when I receive the callback, how do I know which one was clicked? Is there some special identifier? I tried googling and reading the manual but couldn't find a straightforward way.

    I managed to make it work by storing a dictionary of item.GetHashCode and a custom string identifier, and looking up the identifier in callback via clickEvent.target.GetHashCode ... but I'm sure I'm missing something and there are actually elegant ways of doing this?

    Thanks for any info!
     
  2. broots

    broots

    Joined:
    Dec 20, 2019
    Posts:
    54
    Heya, I think you're basically on the money here, I use dictionaries and event.currentTarget


    Code (CSharp):
    1.        
    2.  
    3. private readonly Dictionary<VisualElement, Object> itemClickLink =
    4.     new Dictionary<VisualElement, Object>();
    5. //Populate items somehow
    6.  
    7.  private void OnItemClicked(ClickEvent evt)
    8.         {
    9.             if (!(evt.currentTarget is VisualElement ve)
    10.                 || !itemClickLink.TryGetValue(ve, out var obj))
    11.                 return;
    12.  
    13.             if (evt.clickCount == 1) onItemSelected?.Invoke(obj);
    14.         }
    15.  
     
    Kazko likes this.
  3. RKar

    RKar

    Joined:
    Mar 6, 2019
    Posts:
    22
    if you use one callback action for all elements - try this:

    Code (CSharp):
    1. private void Start()
    2.         {
    3.             VisualElement element = new VisualElement();
    4.  
    5.             element.RegisterCallback<ClickEvent>(ev => CallbackMethod(element));
    6.         }
    7.  
    8.         private void CallbackMethod(VisualElement elem)
    9.         {
    10.             //do stuff
    11.         }
     
    Kazko likes this.
  4. Kazko

    Kazko

    Joined:
    Apr 2, 2014
    Posts:
    82
    Great! This allows me to use VisualElement.userData! I set the data when creating the element, then read it when the element is passed via callback.

    Also, can anything be done with the closure allocations? Rider suggests that "Closure can be eliminated: Method has overload to avoid closure creation" for RegisterCallback method, but I am unable to find or utilize it.
     
  5. RKar

    RKar

    Joined:
    Mar 6, 2019
    Posts:
    22
    May be ev argument have link to target.