MultiColumnListView (Unity 2022.1.0 Beta 1)

Hello,

According to release notes there is a new component for UIToolkit that sound quite interesting and handy.

Unfortunately I could not find any documentation and/or example for it and it does not appear in UIBuilder either. Could you please point me to right page where we could find more info about it?

Thanks.

We are still working on the documentation, and it is not yet exposed in the builder.
At this moment, that component would be for really experienced user only.

The best thing you can do is to have a look here :

I was also interested in this. Is there any timeline when it will be exposed to the UIBuilder?

UI Builder can already support content that contains multi-column listviews and treeviews, however you cannot edit the definition of these controls nor can you add them from the builder’s library just yet. Basically the authoring workflow is coming in the next version, but as I mentioned you can already add it in the Uxml directly.

Here is a typical use in Uxml:

    <MultiColumnListView>
        <Columns>
            <Column id="filename" title="Name" stretchable="true" max-width="250" cell-binding-path="fileName" />
            <Column id="modified_date" title="Modified Date" cell-binding-path="modifiedDate"/>
            <Column id="type" title="Type" max-width="100" cell-binding-path="type"/>
            <Column id="size" title="Size"  width="60" cell-binding-path="size" />
            <TemplateColumn id="edit" title="Edit" stretchable="true" cell-template="EditButton" />
        </Columns>
    </MultiColumnListView>
1 Like

Thanks for info.

Played with it a bit and managed to add it via code in runtime.

The only moment that’s not yet clear is how to use sorting, should I sort .itemsSource manually, is there a callback I can use for that (couldn’t find one) or should we use data binding some way (couldn’t find anything similar to cell-binding-path in code)

Here is a code snippet I use for testing (I’m using it in uitoolkit runtime).

...
void Start()
    {
        _list = new List<ListItem>()
        {
            new ListItem
            {
                f1 = "1_1",
                f2 = "1_2",
                f3 = "1_3",
            },
            new ListItem
            {
                f1 = "2_1",
                f2 = "2_2",
                f3 = "2_3",
            },
            new ListItem
            {
                f1 = "3_1",
                f2 = "3_2",
                f3 = "3_3",
            }
        };

        uiDocument.rootVisualElement.Q<MultiColumnListView>().itemsSource = _list;

        var columns = new Columns();
        columns.Add(new Column
        {
            name = "column1",
            title = "title1",
            bindCell = (x, y) => { OnBindCell(x, y, 0); },
            makeCell = OnMakeCell,
            sortable = true,
        });
        columns.Add(new Column
        {
            name = "column2",
            title = "title2",
            bindCell = (x, y) => { OnBindCell(x, y, 1); },
            makeCell = OnMakeCell,
        });
        columns.Add(new Column
        {
            name = "column3",
            title = "title3",
            bindCell = (x, y) => { OnBindCell(x, y, 2); },
            makeCell = OnMakeCell,
        });
        var mc = new MultiColumnListView(columns);
        mc.itemsSource = _list;
        uiDocument.rootVisualElement.Add(mc);
    }

    private VisualElement OnMakeCell()
    {
        var ve = new VisualElement();
        var label = new Label();
        ve.Add(label);

        return ve;
    }

    private void OnBindCell(VisualElement ve, int index, int columnIndex)
    {
        if (columnIndex == 0) ve.Q<Label>().text = _list[index].f1;
        if (columnIndex == 1) ve.Q<Label>().text = _list[index].f2;
        if (columnIndex == 2) ve.Q<Label>().text = _list[index].f3;
    }
...
1 Like

You can specify your own columnSortingChanged callback when sorting is triggered by the user. Then you have access to the sortedColumns description list so that you perform the sort yourself (like with IMGUI). We leave it to the dev as it would be very cumbersome and probably not performant at all if we decided to provide a default sort out of the box…

This is from the MultiColumnListView APIs:

/// If a column is clicked to change sorting, this event is raised to allow users to sort the tree view items.
public event Action columnSortingChanged;

/// Contains information about which columns are currently being sorted.
/// Note: Use along with the columnSortingChanged event
public IEnumerable<SortColumnDescription> sortedColumns;

/// The collection of sorted columns by default.
public SortColumnDescriptions sortColumnDescriptions;

/// Whether or not sorting is enabled in the multi-column header.
public bool sortingEnabled;
1 Like

Thanks.

Few more questions:

  • Is it normal to get up to 3 columnSortingChanged calls? When I click on a column and it changes sorting mode for example, I’m getting columnSortingChanged is raised 3 times. 1st & 3rd sortedColumns have same info, second time sortedColumns is empty.

7752231--975522--Screenshot_1.png

  • Regarding sortedColumns, each item always has its columnIndex value = -1, (SortColumnDescription.columnIndex). Is it expected to be -1, what is the purpose of this property? I was assuming that it should point to Columns Collection of the MultiColumnListView.

PS: Happy Holidays

I would say it all depends on how many MCLV instances you have and if they have any sort definition in the Uxml…can you share yours?

I’m using an empty uxml for uidocument and adding MultiColumnListView by code in runtime. Here is the code I use for testing.

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;

public class Test : MonoBehaviour
{
    public class ListItem
    {
        public string f1;
        public string f2;
        public string f3;
    }

    public UIDocument uiDocument;
    private List<ListItem> _list;
    private MultiColumnListView _mclv;

    void Start()
    {
        _list = new List<ListItem>()
        {
            new ListItem
            {
                f1 = "1_1",
                f2 = "1_2",
                f3 = "1_3",
            },
            new ListItem
            {
                f1 = "2_1",
                f2 = "2_2",
                f3 = "2_3",
            },
            new ListItem
            {
                f1 = "3_1",
                f2 = "3_2",
                f3 = "3_3",
            }
        };

        var columns = new Columns();
        columns.Add(new Column
        {
            name = "column1",
            title = "title1",
            bindCell = (x, y) => { OnBindCell(x, y, 0); },
            makeCell = OnMakeCell,
            sortable = true,
        });
        columns.Add(new Column
        {
            name = "column2",
            title = "title2",
            bindCell = (x, y) => { OnBindCell(x, y, 1); },
            makeCell = OnMakeCell,
        });
        columns.Add(new Column
        {
            name = "column3",
            title = "title3",
            bindCell = (x, y) => { OnBindCell(x, y, 2); },
            makeCell = OnMakeCell,
            stretchable = true,
        });

        _mclv = new MultiColumnListView(columns);
        _mclv.sortingEnabled = true;
        _mclv.columnSortingChanged += OnColumnSortingChanged;
        _mclv.itemsSource = _list;

        uiDocument.rootVisualElement.Add(_mclv);
    }

    private void OnColumnSortingChanged()
    {
        UnityEngine.Debug.Log($"===> OnColumnSortingChanged");
        foreach (var column in _mclv.sortedColumns)
        {
            UnityEngine.Debug.Log($"--- columnName: {column.columnName} direction: {column.direction} columnIndex: {column.columnIndex}");
        }
    }

    private VisualElement OnMakeCell()
    {
        var ve = new VisualElement();
        var label = new Label();
        ve.Add(label);

        return ve;
    }

    private void OnBindCell(VisualElement ve, int index, int columnIndex)
    {
        if (columnIndex == 0) ve.Q<Label>().text = _list[index].f1;
        if (columnIndex == 1) ve.Q<Label>().text = _list[index].f2;
        if (columnIndex == 2) ve.Q<Label>().text = _list[index].f3;
    }
}

As a follow up, tried it in Beta 3 and it has same behaviour.

Same in Beta 4, @sebastiend-unity could you please elaborate?

Can these be displayed contextually? – i.e. Only show “filename” column when column “type” contains “file” as the type of data?

Filed a bug report, CASE 1401151. Hope this helps.
@sebastiend-unity , @SimonDufour

1 Like

I’m in unity version 2022.1.17f1 and I still can’t configure MultiColumnListView from UIBuilder. Did this get missed or something?

““Basically the authoring workflow is coming in the next version”” hmmm

2 Likes