ListView.itemSource does not work with custom types.

I have a collection: List which I wanted to use as the source (as ListView just passes this to the Bind handler anyhow, and relies on it’s size).

            list                = root.Q<ListView>();
            list.makeItem       = () => new Label();
            list.bindItem       = (e, i) => (w as Label).text = Checklist.Items[i].Name;
            list.itemsSource    = Checklist.Items(); //List<CheckListItem>()
            list.selectionType  = SelectionType.Single;
            list.onItemChosen   += obj => OnItemChosen(obj as CheckListItem);

The above does literally nothing when I call Refresh().

itemSource seems to only work from a collection of strings, so to make it work, I had to do this:

        private List<string> GetProxy()
        {
            var list = new List<string>();
            for (var i = 0; i < Checklist.ChecklistItems.Count; i++)
                list.Add(Checklist.ChecklistItems[i].Name);
            return list;
        }

And everytime I need to refresh the list I have to do:

            list.itemsSource = GetProxy();
            list.Refresh();

And then it magically works and displays my items (while I now have to synchonize an extra list of strings just for this to actually function on every refresh)…

Since we have to setup our own makeitem, binditem and source handlers, why does this not work when i pass in a source of List<CustomClass>?

Seems like a bug.

Passing in string lists, also means now that onItemChosen now returns a string instead of my custom class type, so now I have to work with indexes instead.

It may not matter, but in bind you’re accessing a different array than ItemsSource, now I feel like that shouldn’t cause a problem, but maybe it is.

edit: Though, I suppose technically that is the same collection object

I have ListView working with a collection of structs working fine.

                optionList.bindItem = (v, i) =>
                {
                    Label label = v as Label;
                    var suggestOption = (SuggestOption)optionList.itemsSource[i];

                    label.text = suggestOption.Name;
                    label.userData = suggestOption;
                };

Ah yes it is the same collection object (which are classes, not structs), which had been renamed.
For me it still refuses to work though :(.

Hey @MoruganKodi I made a simple example using the List of strings

private List<string> itemsSource = new List<string>();

public void OnEnable()
{
    var root = this.rootVisualElement;

    itemsSource.Add("Apple");
    itemsSource.Add("Banana");
    itemsSource.Add("Orange");

    myListView = new ListView(itemsSource, 20, MakeItem, BindItem);
    myListView.style.width = 200;
    myListView.style.height = 200;
   
    root.Add(myListView);
}

private void BindItem(VisualElement container, int index)
{
    (container as Label).text = itemsSource[index];
}

private VisualElement MakeItem()
{
    return new Label();
}

And a similar example using a Fruit class.

private class Fruit
{
    public string Name;
}

private List<Fruit> itemsSource = new List<Fruit>();

public void OnEnable()
{
    var root = this.rootVisualElement;
   
    itemsSource.Add(new Fruit {Name = "Apple"});
    itemsSource.Add(new Fruit {Name = "Banana"});
    itemsSource.Add(new Fruit {Name = "Orange"});

    myListView = new ListView(itemsSource, 20, MakeItem, BindItem);
    myListView.style.width = 200;
    myListView.style.height = 200;
   
    root.Add(myListView);
}

private void BindItem(VisualElement container, int index)
{
    (container as Label).text = itemsSource[index].Name;
}

private VisualElement MakeItem()
{
    return new Label();
}

Both were working identical for me. Can you give a window script or an example project? I am curious to test it, Thank you!

1 Like