This is the fifth part in the series: UI Toolkit runtime bindings system
- Part 1: Introduction to the runtime binding system.
- Part 2: Overview of the available binding types.
- Part 3: Instrumenting your types and custom elements for runtime bindings.
- Part 4: Type conversions.
- Part 5: Tips & performance considerations. (This post)
- Part 6: Current limitations & what's next.
This part will provide some insights that will help you get the most performance when using the UI Toolkit runtime bindings system.
- Avoid adding per-element state to your own binding types.
- When your binding type should only be updated when a change is detected in the source, be sure to set the
updateTrigger
toBindingUpdateTrigger.OnSourceChanged
. - When your binding type should only be updated manually, be sure to set the
updateTrigger
toBindingUpdateTrigger.WhenDirty
. - Whenever possible prefer to use the
OnActivated
,OnDeactivated
orOnDataSourceChanged
callbacks instead of theUpdate
callback.
- Be sure to set the appropriate
bindingMode
for your use case. For example, when changes in the UI should not be replicated in the source or if the UI isreadonly
, set thebindingMode
toBindingMode.ToTarget
to avoid data corruption.
- Prefer to use C# properties instead of fields when defining a bindable property. This will give a chance to do validation, notify of changes when using versioning, etc.
- Avoid creating C# properties that do a lot of work. If necessary, do the work as required and use a cached value for the bindings.
- Avoid notifying changes where no change happened (i.e. not checking if the value actually changed before sending the notification).
- Prefer to use versioning when creating a data source. For maximum performance, use both versioning features together.
- As much as possible, prefer to write data sources that will act as a buffer between your data and the UI rather than using the data directly.
- This will make it easier to control the flow of the data and be aware of the changes coming from the UI. This will also allow to control when the data is updated.
- This will make it easier to keep all UI data in one spot and keep paths as short as possible.
- This will allow you to keep the original data as lean and clean (no need to instrument your types, etc.)
- This will allow you to prepare the data for UI (i.e. manually converting the data in your code will be faster than defining and setting conversion methods on binding objects).
- Although it is unavoidable in some cases (i.e. anything dealing with
Enum
), avoid writing conversion delegates that allocate memory. - Avoid doing any lengthy work in a converter.
- Prefer to bake in the type conversion in your data source than relying on per-binding conversions.
- When implementing a custom field, avoid using bindings to update the internal data of the control (i.e. a
Vector3Field
should not use bindings to keep thex
,y
andz
sub-elements in sync). - Avoid creating C# properties that do a lot of work. If necessary, do the work as required and use a cached value for the bindings.
- Avoid notifying changes where no change happened (i.e. not checking if the value actually changed before sending the notification).
- Prefer to use shorter data source paths whenever possible. This is unavoidable, the longer the path, the more work we need to do to extract or set a value.
- Note that while we will internally cache the resolved paths, we will still combine all relative paths.
- Avoid creating property paths that have more than four parts, as it will allocate memory for the additional parts.
- Prefer to construct complex paths by combining parts instead of creating a
Unity.Properties.PropertyPath
with astring
.