How can I dispatch custom event in UIToolkit?

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 :frowning:
  • Is there any example for best practice :slight_smile:
    public class LayoutChangeEvent : EventBase<LayoutChangeEvent>
    {
        protected override void Init()
        {
            base.Init();
            this.LocalInit();
        }

        private void LocalInit()
        {
            this.bubbles = true;
            this.tricklesDown = true;
        }

        public LayoutChangeEvent() => this.LocalInit();
    }
using var evt = LayoutChangeEvent.GetPooled();
visualElement.SendEvent(evt);
3 Likes

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.

FYI @benoitm-unity @uBenoitA @spiney199 @SimonDufour
Sorry for direct approach but any chance we can get a bit of help with problem in this thread please?

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.

public class ResponsiveElement : VisualElement{
    public event Action buttonClick = delegate{};

    public void invokeButtonClickEvent(){
        buttonClick();
    }
}

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.

Thanks @mikemohan . 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…

public delegate void OnClick(BehaviourReferenceItem reference);
public OnClick onClick;

So I can then register callbacks on creation, eg:

button.clicked += onClick?.Invoke(this);

Ah… It might be worth to mention ListView.bindItem is being called a lot on each element so had to replace

refItem.onClick += (item) => {  ... }

with

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.

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(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.

Exact same code, exact same problem.
I really want this to work, and really don’t want to use other event systems

Make sure to set the target of the event before sending.

using var evt = LayoutChangeEvent.GetPooled();
evt.target = visualElement;
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.

2 Likes

@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?

Make sure to set the target of the event before sending

Thanks, this works for me.

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: Unity - Manual: Dispatch events

I see thanks

Tested using Unity 6, and it silently breaks when a target is not specified.

public class ElementSelectedEvent : EventBase<ElementSelectedEvent>
{
}

using var e = ElementSelectedEvent.GetPooled();
// e.target = target;
target.SendEvent(e);

Quite an unfortunate discovery as the manual does not instruct doing so.

Another thing you need is configuring whether the event is bubbling or trickling down. It seems that both are initially false.

So, you should have something like this:


public class CustomEvent : EventBase<CustomEvent>
{
    // event properties

    public CustomEvent()
    {
        LocalInit();
    }

    protected override void Init()
    {
        base.Init();
        LocalInit();
    }

    private void LocalInit()
    {
        // Set each to either true or false, depending on what you need.
        bubbles = true;
        tricklesDown = true;
    }
}

I also found this somewhere on the internet, and not in the docs…