Link UXML VisualElements and Scripts

Hello!

I’ve been a fan of UI Toolkit for a while and have always used it by defining fields and creating the VisualTree through a script. However, I’m taking on a new project and designing a larger interface with many tabs (>10) and VisualElements within each tab (>10) that would be cumbersome to design through code, so I’ve given a chance to design it through the UI Builder.

I’ve found it a bit odd, as sometimes it can be very laggy, although disabling the live reload option on the Game window helped a bit. Anyways, I’ve completed the design fairly well and loved to use USS, as it helps standardizing my code.

The problem I’m having right now is that I don’t think I understood the purpose of UI Builder correctly. I’ve created a main tab UXML file and different UXML files for each tab, so that I could instantiate them when a button inside the main tab was clicked. However, I’m getting frustrated by discovering that there doesn’t seem to be a clear way to simply assign a behaviour to a button. For example: if I were to assign an event to a button on the main tab that triggered the opening of another tab next to it (it is a side menu), I’d have to first query all buttons in the main tab and register them to an event handling function to discern what’s going on and opening the corresponding tab. This gives me a couple of problems:

  1. Polling a hierarchy of elements trying to match it to a specific button name is not what I was looking for, so I guess that the purpose of UI Builder and UXML is to actually build generic interfaces, not specific ones as I was expecting.

  2. If I were to open a tab from the main one, then I’d have a few options that could be toggled or not. If one of them is toggled, to know which one it was, I’d have to poll all elements from the tab that was opened from the main one, register them to events and when it was triggered, I’d have to sort which toggle was clicked to know which method to execute, which is very cumbersome.

So my question is: why would I use UI Builder if I have to query all elements from the window in a script to get any information from it? This is why I think I understood it’s purpose wrong. Maybe if there are few buttons this would be useful, but with over 100 buttons, it gets very complicated. I guess that with bindings I could display data on it, but to input behaviours such as method triggering and etc, I guess it’d be a lot of trouble to go through, right?

Cheers!

UI Toolkit is based upon a Model-View pattern, like the web dev workflows its based upon. Ergo a defined separation of the visual layer and the logic/data layer, and a pretty common pattern you’ll see in programming architecture in general.

Intent being that your UXML is just there to be the visual representation of your UI, and you manipulate them ‘remotely’ via your monobehaviours. Similarly your styling is done through USS (AKA to CSS) and again, mostly separate from your visual heirarchy. It can seem a bit odd when you’re used to uGUI and Unity’s game object/component architecture in general which generally has zero of this separation. And like everything it has upsides and downsides.

It also helps to think about it from the perspective of production teams. With UI Builder you can have UI designers freely design UI, and programmers to implement behaviour without stepping on one another’s toes.

But you don’t have to stick with this pattern if you don’t want to. I often make custom controls that are specific to their use and tie my representation and logic together a bit more. This process is a lot easier in 2023.2+ as well. Often my visual tree assets are only a few visual elements, with some custom ones that generate the rest of the display. And then all styling is done through USS style sheets.

To use your button example, you can just make custom buttons that do your specific logic. Or they don’t have a specific implementation but exist just so you can query them in a type-safe manner. Something like this:

[UxmlElement]
public partial class CraftItemButton : UnityEngine.UIElements.Button
{
    public CraftItemButton()
    {
        name = "craft-item-button";
        text = "CRAFT";
    }
}

// elsewhere
var craftItemButton = rootVisualElement.Q<CraftItemButton>();
craftItemButton.clicked += CraftItem;

In newer versions you can also reference assets in your custom visual elements, though it follows the same rule as other assets, namely that you can’t reference scene-objects. But it makes it possible to perhaps reference scriptable objects to modularly define your UI behaviour.

I haven’t played with data-binding outside of the editor, but I’m close to that point with my current project.

In any case, it’s a bit different to how you’d normally deal with Unity, and the floor is higher than uGUI, but you have a lot more flexibility in how you approach your UI design/implementation now.

Hi, mate! First, thanks a lot for replying to me, I’ve been looking at the forums for a bit and learning a lot from previous comments you left on other threads, so thanks for that too :).

Your through explanation is really awesome and, in fact, you’ve hit the nail in the head with the model-view pattern, because that’s exactly why I’ve been going through this route. I’m exploring this pattern for the UI to have a clear separation of its representation and its behaviours, so it fits like a glove. I’ve got a handle on USS and I think it is interesting, especially for standardizing things. I don’t want to go through all the troubles of dealing with IMGUI-type definitions of a UI… it’s so intertwined that maintaining it is a complex matter.

Your idea of making a single-use custom control is good, but at the same time, I’d need to create multiple custom controls and then reference them again… I don’t think this bridges the gap as I wanted it too. From a scaling/maintenance point of view, this seems a bit odd, I think.

I’ve been looking at binding lately, as suggested by @uDamian in this thread . It may be a way to get what I want, but I haven’t been able to get super deep into it yet.

All in all, I think that even if I had all visual elements related to variables within multiple C# scripts, it’d still be a complicated code, as there are over a hundred visual elements, so maybe I’m trying to find a clever solution for something that is intrinsically complex. I’m not considering reworking the UI completely at this point because it is not my decision to make, but it is in the plans for the future. Even so, I guess that I could have a script for every part of the different tabs and try to reduce the clutter of so many elements in this way.

If you have any insight or materials about binding, let me know!

Cheers!

I mean in most situations I try to keep my UI as simple as possible, though, naturally, this isn’t possible in all projects.

Then otherwise, if the UI is simple enough I will hand-design the layout and query the small amount of needed UI elements.

More elaborate stuff I tend to generate the elements via code. And it goes without saying this is required in a lot of cases, such as stuff like inventories. This is my approach most of the time anyway as I prefer working in code.

I’d be curious to know what sort of UI for what sort of project you’re working with. Maybe I can suggest ways to handle the UI.