Twoway Binding for an int not working

Hey, I have a custom List Element (it creates elements and adds a callback when they are clicked to change the _selectedElement property, nothing else is important).

    [UxmlElement]
    [Serializable]
    public partial class ListElement : BindableElement
    {
        private readonly ObjectPool<VisualElement> pool;
        private readonly List<VisualElement> templates = new();

        private IList items = new List<object>();
        
        public ListElement()
        {
            this.pool = new ObjectPool<VisualElement>(() => this.itemTemplate!.Instantiate().Children().FirstOrDefault());
        }

        [UxmlAttribute("item-template")]
        [CreateProperty]
        public VisualTreeAsset itemTemplate { get; set; }

        [CreateProperty]
        public IList itemsSource
        {
            get => this.items;
            set
            {
                Debug.Log($"setting list-items to {value}");
                if (!this.items.Equals(value) || this.items.Count != value.Count)
                {
                    this.items = value;
                    this.Rebuild();
                }

                this.NotifyPropertyChanged(nameof(this.itemsSource));
            }
        }

        private int _selectedElement = -1;

        
        [UxmlAttribute("selected-element")]
        [CreateProperty]
        public int selectedElement
        {
            get => this._selectedElement;
            set
            {
                _selectedElement = value;
                Debug.Log($"Changing selected element to {value}");
                this.NotifyPropertyChanged((nameof(this._selectedElement)));
            }
        }

        private void Rebuild()
        {
            Debug.Log("rebuilding list");
            if (this.itemTemplate == null)
            {
                throw new InvalidOperationException($"{nameof(this.itemTemplate)} has not be set");
            }
            Debug.Log($"We have {items.Count} items");

            // Add anything new
            for (var i = this.templates.Count; i < this.itemsSource.Count; i++)
            {
                var item = this.pool.Get();
                this.Add(item);
                this.templates.Add(item);
                item.dataSource = this.itemsSource;
                item.dataSourcePath = PropertyPath.FromIndex(i);
                var i1 = i;
                item.RegisterCallback<ClickEvent>(evt =>
                {
                    selectedElement = i1;
                    Debug.Log("Clicked an element");
                });
            }

            // Remove shrinking
            for (var i = this.templates.Count - 1; i >= this.itemsSource.Count; i--)
            {
                var item = this.templates[i];
                this.Remove(item);
                this.templates.RemoveAt(i);
                this.pool.Release(item);
            }
        }
    }

Together with a a datasource:

public class DayState : ScriptableObject, INotifyBindablePropertyChanged
{
    public List<TimeSlotSO> timeSlots;
    private int _selectedTimeSlot = -1;

    [CreateProperty] public int SelectedTimeSlot
    {
        get => _selectedTimeSlot;
        set
        {
            Debug.Log($"Data source time slot changed to {value}");
            _selectedTimeSlot = value;
            TimeSlotSelected.Invoke();
        }
    } 
}

In the UXML I am binding as such:

            <UI.ListElement.ListElement name="ListElement" item-template="project://database/Assets/UI/Panels/DailyActions/TimeSlotElement.uxml?fileID=9197481963319205126&amp;guid=3c25f402937f84b47b0ce3cd06e44b39&amp;type=3#TimeSlotElement">
                <Bindings>
                    <engine:DataBinding property="selectedElement" data-source-path="SelectedTimeSlot" binding-mode="TwoWay" />
                    <engine:DataBinding property="itemsSource" data-source-path="timeSlots" binding-mode="ToTarget" />
                </Bindings>
            </UI.ListElement.ListElement>

I know the binding works, since the second binding works (the one where I bind itemsSource), the items are displayed.

However, when I click an element, only Changing selected element to is logged in the console, i.e. the handler in the VisualElement itself.

However, Data source time slot changed to is not logged and the value in the data source also doesn’t change. Am I missing something?

Hi! I believe the selectedElement change is not propagated correctly because the NotifyPropertyChanged is not sending the correct property name:

This will send _selectedElement instead of selectedElement.

Hope this helps!

1 Like