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. Dismiss Notice

Question How can I dispatch custom event in UIToolkit?

Discussion in 'UI Toolkit' started by Jamesika, Sep 25, 2022.

  1. Jamesika

    Jamesika

    Joined:
    May 13, 2017
    Posts:
    5
    Here is my custom event class, and I call SendEvent function as Manual said, but It doesn't work at all.
    - What does I miss :(
    - Is there any example for best practice :)


    Code (CSharp):
    1.  
    2.     public class LayoutChangeEvent : EventBase<LayoutChangeEvent>
    3.     {
    4.         protected override void Init()
    5.         {
    6.             base.Init();
    7.             this.LocalInit();
    8.         }
    9.  
    10.         private void LocalInit()
    11.         {
    12.             this.bubbles = true;
    13.             this.tricklesDown = true;
    14.         }
    15.  
    16.         public LayoutChangeEvent() => this.LocalInit();
    17.     }
    18.  
    Code (CSharp):
    1.  
    2. using var evt = LayoutChangeEvent.GetPooled();
    3. visualElement.SendEvent(evt);
    4.  
     
    achimmihca and IndieForger like this.
  2. IndieForger

    IndieForger

    Joined:
    Dec 31, 2012
    Posts:
    92
    Bump! I am literally stuck with the same problem. I have spend last long hours with docs and honestly can't figure this out. I hope someone can help with this.
     
  3. IndieForger

    IndieForger

    Joined:
    Dec 31, 2012
    Posts:
    92
  4. mikejm_

    mikejm_

    Joined:
    Oct 9, 2021
    Posts:
    346
    I am not an expert on event management but one way to deal with events is to create a derived class from VisualElement that has the events you want built in.

    Code (csharp):
    1. public class ResponsiveElement : VisualElement{
    2.     public event Action buttonClick = delegate{};
    3.  
    4.     public void invokeButtonClickEvent(){
    5.         buttonClick();
    6.     }
    7. }
    Not sure if this will help you but now if you make an object of the class ResponsiveElement you can use it like a VisualElement but it also has an event you can subscribe things to or invoke from outside the class.
     
  5. IndieForger

    IndieForger

    Joined:
    Dec 31, 2012
    Posts:
    92
    Thanks @mikejm_. That's actually what I ended up doing last night.

    To be honest I think I am getting a bit lost in UI Toolkit events, which seem to work very differently. I have spent hours with documentation and UnityCSReference repository trying to wrap my head around. Haven't gotten there yet...

    Ended up creating UI element builder classes that extend from VisualElement and use events regular event / delegates even for simple things like button clicks. For examples...

    Code (CSharp):
    1. public delegate void OnClick(BehaviourReferenceItem reference);
    2. public OnClick onClick;
    So I can then register callbacks on creation, eg:
    Code (CSharp):
    1. button.clicked += onClick?.Invoke(this);
     
  6. IndieForger

    IndieForger

    Joined:
    Dec 31, 2012
    Posts:
    92
    Ah... It might be worth to mention
    ListView.bindItem
    is being called a lot on each element so had to replace
    Code (CSharp):
    1. refItem.onClick += (item) => {  ... }
    with
    Code (CSharp):
    1. refItem.onClick = (item) => {  ... }
    to avoid delegates being called multiple times.

    I would like to find more elegant way to handle communication between UI components but since code seems to be relatively easy to read I think I will settle for what I have for now.
     
  7. achimmihca

    achimmihca

    Joined:
    Feb 13, 2016
    Posts:
    266
    I have the same issue. How to properly send custom events in UIToolkit?

    - I have a MyCustomEvent, which extends EventBase
    - I send this event in a custom VisualElement using SendEvent(MyCustomEvent.GetPooled())
    - I registered to this event of my custom VisualElement using
    myVisualElement.RegisterCallback<MyCustomEvent>(evt => Debug.Log("Event received"))

    Nothing happens, the event is not received and nothing is logged.

    What more could there be to register and send events???
    I am not finding documentation about this.
     
  8. cz-ds

    cz-ds

    Joined:
    Nov 10, 2021
    Posts:
    1
    Exact same code, exact same problem.
    I really want this to work, and really don't want to use other event systems
     
  9. griendeau_unity

    griendeau_unity

    Unity Technologies

    Joined:
    Aug 25, 2020
    Posts:
    230
    Make sure to set the target of the event before sending.

    Code (CSharp):
    1. using var evt = LayoutChangeEvent.GetPooled();
    2. evt.target = visualElement;
    3. visualElement.SendEvent(evt);
    The event will then be transmitted along the propagation path from the root of the panel to that element and back up.
     
    achimmihca likes this.
  10. npatsiouras_ntua

    npatsiouras_ntua

    Joined:
    Feb 11, 2023
    Posts:
    12
    @griendeau_unity My question is, as it is above, thinking LayoutChangeEvent is a custom event, can you sendEvent with a parent as target and register a handler in a child for this custom event? Do we have to set currentTarget to target a specific recipient further down the hierarchy? If so, we'd basically have to send multiple if we target multiple recipients?

    Let me give an example scenario. I have this GraphView based tool where I'm adding output ports to a GraphView Node by contextual menu. Within the same node's extensionContainer, I have a List of items where each item contains a property for which I intended a DropdownField whose choices are the names/guids of the Output ports of the Node.

    I thought I'd use custom events to propagate the PortAdded/Removed/Renamed events to the DropdownField of each item in that list.

    Technically it didn't work in the sense that I'm issuing the event with the Node as the target, but I'm also regitering the handler on said Node, not on the items of the List which I'd expect. Currently it works by querying all DropdownField children because by design they are only used in that particular List Item class, so it works.

    List Items are drawn using a PropertyDrawer and in the drawer, I register callbacks for all 3 of the above events but cannot listen to them, regardless of TrickleDown or BubbleUp.

    Would I have to target each DropdownField specifically(evt.currentTarget = DropdownFieldInstance) and SendEvent? Or am I missing sth?
     
  11. achimmihca

    achimmihca

    Joined:
    Feb 13, 2016
    Posts:
    266
    > Make sure to set the target of the event before sending

    Thanks, this works for me.
     
  12. griendeau_unity

    griendeau_unity

    Unity Technologies

    Joined:
    Aug 25, 2020
    Posts:
    230
    Events in UI Toolkit will go as far as the target of the event. So if the target is the parent, it won't reach its children. If you're targeting known elements and don't need event propagation on other elements in the hierarchy, I would probably go with Queries to collect elements and regular C# callbacks instead.

    You can have a look at the manual for more info on event dispatching if needed: https://docs.unity.cn/Manual/UIE-Events-Dispatching.html
     
  13. npatsiouras_ntua

    npatsiouras_ntua

    Joined:
    Feb 11, 2023
    Posts:
    12
    I see thanks