To bind a property of a visual element to a data source in C#, create an instance of DataBinding
. With this binding type, you can define a dataSource
and a dataSourcePath
directly on the binding instance.
To create a runtime binding in C#, follow these steps:
The following example created a binding object and registers it to a visual element. It’s equivalent to this UXML in the Get started with runtime binding example:
var dataSource = ScriptableObject.CreateInstance<ExampleObject>();
var root = new VisualElement
{
name = "root",
dataSource = dataSource
};
var vector3Field = new Vector3Field("Vec3 Field");
vector3Field.SetBinding("label", new DataBinding
{
dataSourcePath = new PropertyPath(nameof(ExampleObject.vector3Label)),
bindingMode = BindingMode.ToTarget
});
vector3Field.SetBinding("value", new DataBinding
{
dataSourcePath = new PropertyPath(nameof(ExampleObject.vector3Value))
});
root.Add(vector3Field);
var floatField = new FloatField("Float Field") { value = 42.2f };
floatField.SetBinding("value", new DataBinding
{
dataSourcePath = new PropertyPath(nameof(ExampleObject.sumOfVector3Properties))
});
root.Add(floatField);
var label = new Label("Label")
{
dataSourcePath = new PropertyPath(nameof(ExampleObject.dangerLevel))
};
// Here, we do not need to set the dataSourcePath because we will only use two bindings and they will use the same path,
// so we set the dataSourcePath on the Label directly instead.
var binding = new DataBinding
{
bindingMode = BindingMode.ToTarget
};
// Add a custom float -> string converter
binding.sourceToUiConverters.AddConverter((ref float v) =>
{
return v switch
{
>= 0 and < 1.0f/3.0f => "Danger",
>= 1.0f/3.0f and < 2.0f/3.0f => "Neutral",
_ => "Good"
};
});
// Add a custom float -> StyleColor
binding.sourceToUiConverters.AddConverter((ref float v) => new StyleColor(Color.Lerp(Color.red, Color.green, v)));
// Since the binding is targeting the same data source property, we can re-use the same instance.
label.SetBinding("text", binding);
label.SetBinding("style.backgroundColor", binding);
root.Add(label);
You can use the following methods to manage binding objects:
You can create the bindable properties in the same way as other data sources, which means that you can also use VisualElement
types as data sources. The main difference between a VisualElement
type and other data sources is that VisualElement
types come with built-in versioning. You must use the built-in versioning of a VisualElement
type to propagate changes.
To report a change, call the NotifyPropertyChanged
method. This method takes a BindingId
that identifies the property that changed. The following example shows how to report a change:
// Creates a static readonly BindingId that is unique to this type. This is used to identify the property.
public static readonly BindingId intValueProperty = nameof(intValue);
private int m_IntValue;
[CreateProperty]
public int intValue
{
get => m_IntValue;
set
{
if (m_IntValue == value)
return;
m_IntValue = value;
// This instructs the binding system that a change occured.
NotifyPropertyChanged(intValueProperty);
}
}
Follow these tips and best practices to optimize performance:
value
property of a Vector3Field
, the binding ID must be Vector3Field.valueProperty
.x
, y
, and z
sub-elements for a Vector3Field
. Instead, use a binding to synchronize the value
property of the Vector3Field
with a Vector3
property of a data source.UI Toolkit doesn’t report changes in element.style
and element.resolvedStyle
. Therefore, you can use binding instances to target the resolved style of an element but can’t track changes to them.