How stop Label value changed from being applied back to bound SerializedProperty?

I’m working on an editor for my custom settings on the Project Settings window. As in the screenshot bellow, the left panel is a ListView whose items are populated according to this property DatabaseSettings[] databases inside my ScriptableObject. Each item of that ListView is just a Label bound to the DatabaseSettings.name property.

As you can see here, whenever we perform searching on the Project Settings window, matching texts will be highlighted. Actually, the original plain texts will be replaced with rich texts each includes some <color> and <mark> tags.

However, this causes a problem: the value of Label is changed by search function, thus its “value change event” is invoked, results in my name property is updated with the rich text value of that Label.

image

This is the function assigned to bindItem callback on the ListView.

static void BindItem(VisualElement root, int index, SerializedProperty dbListProperty)
{
    var nameProperty = dbListProperty.GetArrayElementAtIndex(index)
        .FindPropertyRelative(nameof(DatabaseSettings.name));

    var label = root.Q<Label>(className: Constants.NAME);
    label.BindProperty(nameProperty);
}
var listView = new ListView {
    makeItem = MakeItem,
    bindItem = (root, index) => BindItem(root, index, dbListProperty),
};

If I comment out the line label.BindProperty(nameProperty);, this problem won’t happen anymore.

But that binding is needed here, for the value of each ListView item must update automatically whenever there is a change to DatabaseSettings.name property.

Does anyone know a way to achieve this?

Like a lot of cases where folks use binding, this is probably where TrackPropertyValue makes more sense: Unity - Scripting API: UIElements.BindingExtensions.TrackPropertyValue

2 Likes

Thanks! Actually, I’ve seen it, but I don’t understand how to use. Do you have any example at hand?

Unity has plenty of examples in the UI Toolkit documentation: Unity - Manual: Receive callbacks when a bound property changes

1 Like

Oh right, my bad, I didn’t look closely at these examples.

1 Like

Thanks to the suggestions from @spiney199 I’ve managed to make it works!

static void BindItem(VisualElement root, int index, SerializedProperty dbListProperty)
{
    var nameProperty = dbListProperty.GetArrayElementAtIndex(index)
        .FindPropertyRelative(nameof(DatabaseSettings.name));

    var label = root.Q<Label>(className: Constants.NAME);
    var labelNotifier = (INotifyValueChanged<string>)label;
    labelNotifier.SetValueWithoutNotify(nameProperty.stringValue);

    label.Unbind();
    label.TrackPropertyValue(nameProperty, prop => {
        labelNotifier.SetValueWithoutNotify(prop.stringValue);
    });
}
1 Like