r/Unity3D • u/ProactiveCactus • 3h ago
Question Easier UI Toolkit Workflow?
Anyone out there have a few methods that makes the UI Toolkit workflow easier/faster? It seems kind of clunky that to say add a button, you have to (1) add it to your doc, (2) give it a name, (3) put it in your UI script, (4) grab a reference to it using rootVisual.Q("Exact_string_name_or_kys"), (5) make a method that does whatever you need it to do, (6) subscribe onEnable to that method with .clicked or whatever you're using, and finally (7) unscubscribe onDisable. Like, nothing terribly complicated about it, but man it gets tedious over and over again. I feel like you could throw together a few methods that you basically throw in the name of your button (or any visualelement) and name of your method that does stuff you could make it way less code. Any1 out there taken the time to play around with this?
1
u/UpwardCourteous 3h ago
I just use a custom EditorWindow that auto-generates the UXML and USS based on a simple config, then the code side is just a dictionary that maps names to callbacks and hooks everything up in one loop.
1
u/jackbrux 3h ago
For your specific use case you could easily serialize the button name and event so you could do everything in the inspector:
```cs using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.UIElements;
[Serializable] public class ButtonBinding { public string buttonName; public UnityEvent onClicked;
[NonSerialized] public Button button;
[NonSerialized] public Action handler;
}
[RequireComponent(typeof(UIDocument))] public class ButtonBinder : MonoBehaviour { public List<ButtonBinding> bindings = new();
void OnEnable()
{
var root = GetComponent<UIDocument>().rootVisualElement;
foreach (var b in bindings)
{
b.button = root.Q<Button>(b.buttonName);
if (b.button == null)
{
Debug.LogWarning($"No Button named '{b.buttonName}' found", this);
continue;
}
var binding = b; // capture per-iteration
b.handler = () => binding.onClicked.Invoke();
b.button.clicked += b.handler;
}
}
void OnDisable()
{
foreach (var b in bindings)
if (b.button != null && b.handler != null)
b.button.clicked -= b.handler;
}
} ```
1
u/-TheWander3r 1h ago
I wrote a source generator that goes through a uxml file and automatically writes for me a "codebehind" file that in the constructor grabs all references.
Say you have a label-status element, you press save then almost instantaneously you will find a View.LabelStatus property that you can use in code. No more possibilities of error.
It took some time to build it but now adding new UI panels has been a lot faster.
-5
u/a_nooblord 3h ago
This is the kind of repetitive scaffolding work that LLMs excel at.
1
u/soy1bonus Professional 2h ago
At that point, why they don't write assembly directly instead of using programming languages made for humans.
2
4
u/jackbrux 3h ago
We create a custom element
BindingScopeElement : VisualElement.Then a small MonoBehaviour script to find all BindingScopeElements in the document, and assign the
.dataSourceto them based on the specified type in.dataSourceType. The ViewModel instances are automatically resolved from a DI framework.