ListView with runtime visual element?

Hi,

I’m trying to dynamically populate a list at runtime using ListView but nothing appears and MakeItem/BindItem aren’t being called. I’m creating/populating it in the constructor of a custom VisualElement and adding that to a .uxml file with a label above it.

public class RoomList : VisualElement
{
    public new class UxmlFactory : UxmlFactory<RoomList, UxmlTraits> { }
    public new class UxmlTraits : VisualElement.UxmlTraits { }

    private ListView listView;

    public RoomList()
    {
        IList items = Resources.LoadAll<RoomAsset>("Rooms");
        listView = new ListView(items, 20, MakeItem, BindItem)
        {
            selectionType = SelectionType.Single,
            horizontalScrollingEnabled = true
        };
        listView.style.flexGrow = 1f;
        listView.style.flexShrink = 0f;
        listView.style.flexBasis = 0f;
        listView.onSelectionChange += Debug.Log;
        Add(listView);
        Debug.Log("RoomList constructor" + items.Count);
    }

    private void BindItem(VisualElement element, int index)
    {
        Debug.Log("RoomList BindItem");
        var item = listView.itemsSource[index];
        (element as TextElement).text = (item as RoomAsset).Name;
    }

    private VisualElement MakeItem()
    {
        Debug.Log("RoomList MakeItem");
        //return new Label();
        var ele = new TextElement();
        ele.style.unityTextAlign = TextAnchor.MiddleLeft;
        ele.style.paddingLeft = 5;
        ele.style.flexGrow = 1f;
        ele.style.flexShrink = 0f;
        ele.style.flexBasis = 0f;
        return ele;
    }
}
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    <Style src="Room.uss" />
    <ui:Label text="Rooms" display-tooltip-when-elided="true" style="font-size: 24px;" />
    <RoomList name="RoomList" style="flex-direction: column;" />
</ui:UXML>

If put this in an editor window it does work:

void OnEnable()
    {
        IList items = Resources.LoadAll<RoomAsset>("Rooms");
        listView = new ListView(items, 20, MakeItem, BindItem)
        {
            selectionType = SelectionType.Single,
            horizontalScrollingEnabled = true
        };
        listView.style.flexGrow = 1f;
        listView.style.flexShrink = 0f;
        listView.style.flexBasis = 0f;
        listView.onSelectionChange += Debug.Log;
        rootVisualElement.Add(listView);
    }

Is not possible to use this at runtime? Is there an alternative?

Cheers

Versions:
Unity 2021.1.0b12.2144.20
UI Toolkit 1.0.0-preview.14
UI Builder 1.0.0-preview.13

Hi!

I think you’re doing everything right here. I’m pretty sure the only thing missing is that your RoomList element does not grow. So right now it is probably there, but you can’t see it. A good way to check that is to use the UI Debugger (Window → UI Toolkit → Debugger) and pick the game panel. RoomList’s height is probably 0, so you would have to change its flexGrow/flexShrink attributes or set a minHeight, depending on your needs.

Cheers!

1 Like

Ah thank you, that does seem to work.
I’d like to load another element defined a .uxml file instead of just a label and bind some data to it.
Is there any code samples for that? I’ve only seen uxml files loaded in code via AssetDatabase which is editor only I believe.

Thanks

Yes, AssetDatabase is editor only. The runtime equivalent would be to load from asset bundles, or from the Resources folder with Resources.Load(“path-to-your-asset”). You could also serialize your VisualTreeAsset in a script directly (public variable or a private variable with the [SerializeField] attribute).

There are a few sample, but not exactly for what you want to do. In Package Manager, click on the UI Toolkit package and import samples under the Samples foldout. You can see in there the last option I mentioned, i.e. passing the visual tree asset in scripts. It’s assigned to a UI Document in the examples, but in your case you would call the CloneTree method instead.

Lovely, thanks for the info.

I don’t see UI Toolkit package in Package Manager, only UI Builder.

Think it depends on version / whether you have experimental packages enabled in project settings.

You can add “com.unity.ui”: “1.0.0-preview.14” to your manifest.json.