I’m just trying to implement custom logic on a bindable element. The documentation is absolutely terrible in this regard, and the examples given are needlessly complicated.
This is for an asset so I’m using unity 2021.3.0f
Let just use a simple example:
public class ExampleElement : BindableElement
{
public new class UxmlFactory : UxmlFactory<ExampleElement, UxmlTraits> { }
public new class UxmlTraits : BindableElement.UxmlTraits { }
private Label labelElement;
public ExampleElement()
{
labelElement = new Label();
Add(labelElement);
}
// Example!
public void OnBoundPropertyChanged(string text)
{
labelElement.text = text;
labelElement.style.color = new UnityEngine.Color(Random.value, Random.value, Random.value);
}
}
So I want to bind a property to this by calling root.Q<ExampleElement> ).BindProperty(myStringProp);
For example.
I know it has something to do with SetValueWithoutNotify
but that’s as far as I’ve gotten. Any help would be greatly appreciated.
using System.Drawing;
using UnityEditor;
using UnityEngine.UIElements;
using UnityEngine;
public class ExampleElement : BindableElement, INotifyValueChanged<string>
{
public new class UxmlFactory : UxmlFactory<ExampleElement, UxmlTraits> { }
public new class UxmlTraits : BindableElement.UxmlTraits { }
private Label labelElement;
private string m_Value;
public string value
{
get => m_Value; set
{
if (value == this.value)
return;
var previous = this.value;
SetValueWithoutNotify(value);
using (var evt = ChangeEvent<string>.GetPooled(previous, value))
{
evt.target = this;
SendEvent(evt);
}
}
}
public ExampleElement()
{
labelElement = new Label();
Add(labelElement);
}
public void SetValueWithoutNotify(string newValue)
{
labelElement.text = newValue;
labelElement.style.color = new UnityEngine.Color(Random.value, Random.value, Random.value);
}
}
Okay I figured it this out, the example should probably include something simple like this instead of mixing up Object and Texture fields. I’m not sure if it needs to be this complicated.
1 Like
Further Update.
I’ve completely abandoned UI Toolkits binding system in favor of my own. UI Toolkits binding system is not flexible enough for my needs as I believe you can only bind a single serialized property per element? Where as to have truly reactive programming I need my UI to respond to all kinds of inputs.
The one drawback is I must wrap my data in an Observable class to be notified of changes.
But now my code looks like this:
var Button = new Button();
Button.BindButtonState(myBool);
Button.BindButtonText(myString);
Button.BindButtonTooltip(myBool, trueMessage, falseMessage);
// etc...
etc
You can use the TrackPropertyValue extension method: Unity - Scripting API: UIElements.BindingExtensions.TrackPropertyValue
Which lets a visual element responds to changes from multiple different serialized properties.
The point of normal Binding is to keep the backing serialized data in sync, and auto-dirtying the respective asset containing said data. To that end it only ever needs to really care about one SerializedProperty.
That looks pretty useful. I never came across it in any of the examples.
I’m still using RegisterValueChangedCallback()
So it’s not fair to say I’ve completely abandoned it. Unity 6 I will probably use it due to the support from source generators and Unity.Properties but the 2021.3 version is a bit painful to use.
It’s shown in some of the examples in the manual: Unity - Manual: Receive callbacks when a bound property changes
I would say UI toolkit is most useful in Unity 6 forwards with the runtime binding and source generator systems implemented.