Localization only works on first instance

Hi! I’m working on inventory system using localization and new UIToolkit binding system. Unfortunately i can’t make it work, when I change locale through dropdown in game view or via code only first item in inventory is being updated with localized text. If I change locale and then add new item it will contain correct values but still wont change after that(except first one).
Here’s my item class:

public class ItemStack : INotifyBindablePropertyChanged
{
    private int _quantity;

    public event EventHandler<BindablePropertyChangedEventArgs> propertyChanged;

    [CreateProperty]
    public ItemConfig Config { get; set; }

    [CreateProperty]
    public int Quantity
    {
        get => _quantity;
        set
        {
            if (_quantity == value)
                return;

            _quantity = value;
            OnPropertyChanged();
        }
    }

    private void OnPropertyChanged([CallerMemberName] string property = "") =>
        propertyChanged?.Invoke(this, new BindablePropertyChangedEventArgs(property));

    public ItemStack(ItemConfig config, int quantity)
    {
        Config = config;
        Quantity = quantity;
    }

    public override string ToString() =>
        $"Name: {Config.Name.GetLocalizedString()} Quantity: {Quantity}";
}

Which holds link to simple scriptable object

[CreateAssetMenu(fileName = "New Item Config", menuName = "Inventory/Item Config", order = 0)]
public class ItemConfig : ScriptableObject
{
    [field: SerializeField, DontCreateProperty]
    [CreateProperty]
    public string Id { get; set; }

    [field: SerializeField, DontCreateProperty]
    public LocalizedString Name { get; set; }

    [field: SerializeField, DontCreateProperty]
    public LocalizedString Description { get; set; }
}

This is how I bind item to view

public void AddItem(ItemStack item)
{
    Items.Add(item);
    AddItemView(item);
}

public void AddItemView(ItemStack item)
{
    VisualElement root = _canvas.rootVisualElement;
    VisualElement itemView = _itemTemplate.Instantiate();

    Label nameLabel = itemView.Q<Label>(itemNameLabel);
    Label descriptionLabel = itemView.Q<Label>(itemDescriptionLabel);
    Label quantityLabel = itemView.Q<Label>(itemQuantityLabel);

    itemView.dataSource = item;

    nameLabel.SetBinding("text", item.Config.Name);
    descriptionLabel.SetBinding("text", item.Config.Description);
    quantityLabel.SetBinding("text", new DataBinding
    {
        dataSourcePath = new PropertyPath("Quantity"),
        bindingMode = BindingMode.ToTarget
    });

    root.Q("inventory__container").Add(itemView);
}

Any ideas why it working only on first item?

It works absolutely fine if I’m getting strings manually

public void AddItemView(ItemStack item)
{
    VisualElement root = _canvas.rootVisualElement;
    VisualElement itemView = _itemTemplate.Instantiate();

    Label nameLabel = itemView.Q<Label>(itemNameLabel);
    Label descriptionLabel = itemView.Q<Label>(itemDescriptionLabel);
    Label quantityLabel = itemView.Q<Label>(itemQuantityLabel);

    itemView.dataSource = item;

    item.Config.Name.StringChanged += localizedText => nameLabel.text = localizedText;
    item.Config.Description.StringChanged += localizedText => descriptionLabel.text = localizedText;
    quantityLabel.SetBinding("text", new DataBinding
    {
        dataSourcePath = new PropertyPath("Quantity"),
        bindingMode = BindingMode.ToTarget
    });

    root.Q("inventory__container").Add(itemView);
}

So reason must be in new Localized string binding. It’s not working or I’m using it wrong.
@karl_jones sorry for ping but can you confirm that new localized string binding is working fine with runtime instantiated ui templates? I don’t understand what am I doing wrong here.
Update: after changing it back to using bindings even first item do not respond to changing locale now.

Hey,
Sorry, I missed the notification.
Can you share an example project so i can see if its a bug or issue with the setup?

Sended it in PM

1 Like

Hey,
I’ll respond here so everyone can see it instead of via DM.
This is indeed a bug, one we are aware of. The problem is that you are using the LocalizedString in multiple bindings, While this is supported the data binding system has a limitation when you are using the binding mode WhenDirty. When the locale is changed the LocalizedString marks itself dirty so that the binding system will update, the problem is that it is not able to handle a dirty state across multiple users so only the first binding user gets updated, and then the dirty flag is reset and the other users don’t get an update. For now, you can work around this in 1 of 2 ways:

  1. Change the binding mode to always update:
item.Config.Name.updateTrigger = BindingUpdateTrigger.EveryUpdate;
item.Config.Description.updateTrigger = BindingUpdateTrigger.EveryUpdate;

Do this once and then they will always update themselves. This won’t be as good for performance but will work until we can fix the issue.

  1. Create a copy of the binding per object:
nameLabel.SetBinding("text", new LocalizedString(item.Config.Name.TableReference, item.Config.Name.TableEntryReference));
//Do the same for Description

I have created a bug report Unity Issue Tracker - [Data Bindings] BindingUpdateTrigger.WhenDirty mode does not support multiple bindings

1 Like

Thank you Karl. I will implement your tips until it’s fixed

1 Like

This is fixed in 2023.3 beta 7 if anyone is wondering

1 Like