Out of the three examples that I gave, I would almost always use the first one, as I like to have reusable pieces of UI that behave the same way in different contexts. Those kind of elements are mostly what I was using before the bindings feature and enabling the feature on it only needed two one-line changes (adding the CreateProperty attribute and notifying of the change).
This would be the case for the majority of custom elements. Adding bindings can be done completely on the uxml side and most data binding can be added through code using a single call per property.
However, Iāve seen enough users that want to create and maintain close to 0 custom elements that included the two additional examples. I would recommend to use the first approach, for the stated reasons.
This is still completely supported. Querying visual elements, manually transferring your data and registering value changed callbacks whenever the source needs to be updated is a valid way to go.
@Thygrrr It seems very similar to WPF, which is rather verbose when you are coding it but usually is hidden behind some kind of code-generation via xml tags. Not that it appears that is how it will work here. Itās a step up from, well, absolutely nothing, which is what we have right now.
All that being said, I donāt disagree wtih you either. Iāve written my own databinding in the past for Unity projects via runtime code emitting and when it can be boiled down to just a couple function calls to binding and unbind itās hard to want to go back. Static analysis would be nice but at this point Iād be happy for something that works and comes out within the effective lifetime of UIToolkit.
While Iām not crazy about it Iām used to writting code like that enough that I donāt mind. But honestly, my biggest disappointment is that itās effectively still a year out at best before it can be used in any kind of real project.
@martinpa_unity For me the basic example in the first message isnāt working in latest Unity 2023.2.0b4. I have created a GameObject in the scene with UIDocument and the following TestScript on it.
However when I start I see only the integer field be 0 and no name visible.
Is it possible to get some example projects up on GitHub on how to set this up?
Thank you for the help
@martinpa_unity Thank you that made it work really cool. Still would love to see some example projects that maybe show like more complex examples. (Like the ListView)
We must just be patient, theyāre still busy typing up all that boilerplate for those samples, this canāt be written overnight.
Iāll provide a sample implementation later hopefully when I have a few free hours. Admittedly I got ref fields from .net 8 mixed up, but just POCOs will do the job.
I still think the data source should be passed into a method on the visual element, and that should then construct and return the binding. Not the other way around.
I think the implementation works great when you use the UI Builder. Did try to write the least lines of C# I could. And for me the ListView which I got working quite easily with only a few lines of code.
I assume with some custom VisualElements you can even hide all this and do something like, SetProfileViews(views);
Hi everyone,
Is it possible binding data to USS selectorās properties or custom properties? Such as: I created transition animation with USS selectors and I want to set this animationsā parameters from ābinding data classā.
If you mean to change the values directly in the style sheet instance, then that is not possible. Style sheet selectors are cached and changing their values on the fly would most likely mean a lot of invalidation and it would force a styling pass on any visual hierarchy using that style sheet.
However, there are ways to do this without changing the style sheet instance:
For the style properties, you could bind to the inline styles using the āstyleā prefix as the path (i.e. āstyle.backgroundColorā, āstyle.transitionPropertyā, etc.) This will let you parametrize your animation for a given element.
For the custom style properties, usually, you need to query them in code and deal with them manually, as most custom properties wonāt do anything by default. Note that transitions on custom properties is not currently supported. You can instrument your own custom properties with [CreateProperty] and you should be able to use the binding system on them.
If your animationsā parameters are part of a known ahead of time set (i.e. duration will either be 0ms, 250ms or 500ms), you can also define those in the style sheet and use a binding to add/remove uss classes. When trying to bind to multiple style properties at the same time, this method is probably the best.
Actually Iām using add/remove uss classes with my transition animation. And I avoid to use inline-style for performance considerations.
But it seems, I have to use inline-style for transition parameters.
There is my test transition parameters.
For this example: If I want to control the ātransition-durationā parameter with āBinding Dataā, I have to use ābinding dataā in āinline styleā.
Hi @GameDev273 , Iāll check on the status of this. Unfortunately, the last weeks have been quite bumpy to say the least and itās vacation season at the moment.
Hi @seika850113_1 , event bindings are not supported out of the box, but here is a very quick and dirty example of how it can be achieved using a custom binding:
using System;
using System.Collections.Generic;
using Unity.Properties;
using UnityEngine.UIElements;
namespace Example
{
[UxmlObject]
public partial class ActionBinding : CustomBinding
{
// Caching the delegate used for cleanup purposes.
private readonly Dictionary<VisualElement, Action> m_CachedDelegates = new ();
// Only tracking the registration when the data source context changes. This wouldn't
// pick-up if the targeted `action` changed on the data source.
protected override void OnDataSourceChanged(in DataSourceContextChanged context)
{
if (context.targetElement is not Button button)
return;
// Clean previous callbacks
if (m_CachedDelegates.TryGetValue(button, out var action))
{
button.clicked -= action;
m_CachedDelegates.Remove(button);
}
// Extract the `Action` from the hierarchy and register it.
var source = context.newContext.dataSource;
var path = context.newContext.dataSourcePath;
if (null == source || !PropertyContainer.TryGetValue(ref source, in path, out action))
return;
button.clicked += action;
m_CachedDelegates.Add(button, action);
}
}
}
Hello @martinpa_unity ,
thanks for the example. Iām trying to make it work on a test project, but I canāt pass dataSourcePath to it. What I have in uxml is:
When I break at line 32 of your example (PropertyContainer.TryGetValue(ref source, in path, out action)) I see, that path is empty (isEmpty = true, length = 0). Not sure if CustomBinding has data-source-path attribute exposed, but I donāt see how else I would pass the path to the binding. Do you have an idea of what Iām doing wrong?
On the side note, it feels that the property attribute of a binding shouldnāt be mandatory, as in this case and some other examples of custom bindings released so far, it is not used.
Edit:
I was able to add my own dataSourcePath UXMLAttribute and set that up. I tried it before but got confused by the transformation from dataSourcePath in code to data-source-path in UXML. However, it seems a bit strange that Iām using the context only for data source, but not the dataSourcePath:
// Extract the `Action` from the hierarchy and register it.
var source = context.newContext.dataSource;
//var path = context.newContext.dataSourcePath;
var path = PropertyPath.FromName(dataSourcePath);