MultiColumnListView bindCell and cell-template

Hello,

I’m starting a new project with UI Toolkit. I’m trying to create a MultiColumnListView, and I have a problem when using bindCell in my C# script and cell-template in the UXML file (same problem with cellTemplate in the C# script).

Here is the code :

Main File :

<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Style src="project://database/Assets/UI/Styles/Doc.uss" />
    <engine:MultiColumnListView allow-add="false" allow-remove="false" reorder-mode="Animated" show-bound-collection-size="false" show-border="false" name="MCListView" virtualization-method="DynamicHeight" selection-type="Single">
        <engine:Columns reorderable="false" resize-preview="false" resizable="false">
            <engine:Column name="Col1" title="Col1" stretchable="true" optional="false" sortable="false" cell-template="project://database/Assets/UI/Documents/Template/Test.uxml" resizable="false" />
        </engine:Columns>
    </engine:MultiColumnListView>
</engine:UXML>

Template File:

<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Unity.AppUI.UI.TextField name="Cell" />
</engine:UXML>

C# Script:

// Start is called once before the first execution of Update after the MonoBehaviour is created
private void Start()
{
    // Populate my item list ...

    UIDocument doc = GetComponent<UIDocument>();

    MultiColumnListView multiColumnListView = (MultiColumnListView)doc.rootVisualElement.Query("MCListView");

    multiColumnListView.columns["Col1"].bindCell = (ve, i) =>
    {
        ve.Q<Unity.AppUI.UI.TextField>("Cell").value = list[i];
    };

    multiColumnListView.itemsSource = list;
}

My problem is :

When I start the game with this document, I get this message (Sometimes it work, but most of the time not):

NullReferenceException: Object reference not set to an instance of an object
MainBehaviour+<>c__DisplayClass0_0.<Start>b__1 (UnityEngine.UIElements.VisualElement ve, System.Int32 i) (at Assets/Scripts/UI/Test.cs:24)

I tried to debug it, and in the “bindCell” function the variable “ve” is a “Label” instead to be the content of my cell-template, I think the document is not yet loaded, so the query fail.

So my question is: Am I doing it wrong? Do I need an event to set the “bindCell” function? Can you help me?

Best Regards.

1 Like

Hello,

I found a solution, adding that line in the c# script :

        multiColumnListView.columns["Col1"].makeCell = () =>
        {
            return multiColumnListView.columns["Col1"].cellTemplate.Instantiate();
        };

It’s not very elegant, and it should be done automatically I think.

Do you have a better Idea?

Best Regards.

Hello,

I think I’ve found the problem and maybe a bug.

First, I copied my project to several PCs and that’s where the problem occurred.

To reproduce this problem:

  • Step 1: I fill the “cell-template” with the UI Builder - everything works.

  • Step 2: I rebuild the Library, deleting the “Library” folder from the project.

  • Step 3: Nothing works, I get the exception of the first message.

I think something similar happens when I move the project to another PC.

However, when I use the following code and explicitly specify the template, it works all the time:

<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Style src="project://database/Assets/UI/Styles/Doc.uss" />

    <engine:Template name="test" src="project://database/Assets/UI/Documents/Template/Test.uxml"/>

    <engine:MultiColumnListView allow-add="false" allow-remove="false" reorder-mode="Animated" show-bound-collection-size="false" show-border="false" name="MCListView" virtualization-method="DynamicHeight" selection-type="Single">
        <engine:Columns reorderable="false" resize-preview="false" resizable="false">
            <engine:Column name="Col1" title="Col1" stretchable="true" optional="false" sortable="false" cell-template="test" resizable="false" />
        </engine:Columns>
    </engine:MultiColumnListView>
</engine:UXML>

Do you think I’m right or am I doing something wrong?

Best Regards.

1 Like

Unity 6000.0.26
I’m experiencing a similar issue. I assign an asset to the Cell Template.


After closing and reopening UI Builder, the Cell Template field becomes empty.

and I have this console error:

ArgumentException: Object of type 'UnityEngine.Object' cannot be converted to type 'UnityEngine.UIElements.VisualTreeAsset'.
System.RuntimeType.CheckValue (System.Object value, System.Reflection.Binder binder, System.Globalization.CultureInfo culture, System.Reflection.BindingFlags invokeAttr) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.Reflection.RuntimeFieldInfo.SetValue (System.Object obj, System.Object val, System.Reflection.BindingFlags invokeAttr, System.Reflection.Binder binder, System.Globalization.CultureInfo culture) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
System.Reflection.FieldInfo.SetValue (System.Object obj, System.Object value) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
UnityEditor.UIElements.UxmlSerializedAttributeDescription.SetSerializedValue (System.Object uxmlSerializedData, System.Object value) (at <1de78b4aa977486ba3ff802e2bee6d16>:0)
UnityEditor.UIElements.UxmlSerializer.Serialize (UnityEditor.UIElements.UxmlSerializedDataDescription description, UnityEngine.UIElements.IUxmlAttributes bag, UnityEngine.UIElements.CreationContext cc, System.Boolean serializeOverrides) (at <1de78b4aa977486ba3ff802e2bee6d16>:0)
Rethrow as Exception: Could not set value for cellTemplate with LocalizationToolBoard.NewKey.Key (UnityEngine.UIElements.VisualTreeAsset)
UnityEditor.UIElements.UxmlSerializer:SyncVisualTreeAssetSerializedData(CreationContext, Boolean)
Unity.UI.Builder.VisualTreeAssetExtensions:DeepCopy(VisualTreeAsset, Boolean)
Unity.UI.Builder.BuilderDocumentOpenUXML:LoadDocument(VisualTreeAsset, VisualElement)
Unity.UI.Builder.BuilderDocument:LoadDocument(VisualTreeAsset, VisualElement)
Unity.UI.Builder.BuilderToolbar:LoadDocumentInternal(VisualTreeAsset)
Unity.UI.Builder.BuilderToolbar:LoadDocument(VisualTreeAsset, Boolean, Boolean, String)
Unity.UI.Builder.Builder:LoadDocument(VisualTreeAsset, Boolean)
Unity.UI.Builder.Builder:OnOpenAsset(Int32, Int32)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr, Boolean&)

EDIT: I found a way to reproduce the issue in a separate project. I made a bug report and I will update this post when I get an Issue Tracker link.

1 Like

Here is the Issue Tracker:

I got this in 6000.0.42f1 again, possibly a regression?

Please submit a bug report in Help>Report a bug… and mention the existing case. QA will investigate, it is possible that it regressed.

I am having the same Bug in 6000.3.0f1

Same for me in unity 6000.3.0

I can’t find any active bug report, please submit a bug report with your repro case in Help>Report a bug… and mention the existing case. QA will investigate, it is possible that it regressed.

For anyone encounter this bug, I use the following editor script to check every possible missing reference of cellTemplate and reimport them. You may need to run it 2~3 times until no warning is raised (LaTeX vibe :frowning: ):

    [MenuItem("Custom/Check MultiColumnListView cellTemplate missing")]
    public static void CheckMultiColumnListView()
    {
        string[] uxmlGuids = AssetDatabase.FindAssets("t:VisualTreeAsset");
        foreach (var uxmlGuid in uxmlGuids)
        {
            var assetPath = AssetDatabase.GUIDToAssetPath(uxmlGuid);

            if (!assetPath.StartsWith("Assets/"))
                continue;

            VisualTreeAsset vta = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(assetPath);

            // Debug.Log($"vta.name={vta.name}");

            var el = vta.CloneTree();
            var multiColumnListViews = el.Query<MultiColumnListView>().ToList();
            if (multiColumnListViews.Count > 0)
            {
                Debug.Log($"vta.name={vta.name} (assetPath={assetPath}, uxmlGuid={uxmlGuid})");
                foreach (var mclv in multiColumnListViews)
                {
                    Debug.Log($"mclv.name={mclv.name}");
                    var hasMissing = false;
                    foreach (var col in mclv.columns)
                    {
                        if (col.cellTemplate != null)
                        {
                            Debug.Log($"col.title={col.title}, col.cellTemplate.name={col.cellTemplate.name}");
                        }
                        else
                        {
                            Debug.LogWarning($"cellTemplate missing: col.title={col.title}, col.cellTemplate={col.cellTemplate}");
                            hasMissing = true;
                        }
                    }
                    if (hasMissing)
                    {
                        AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.Default);
                        Debug.LogWarning("Reimporting...");
                    }
                }
            }
        }
    }

Also I have enforced a cellTemplate check in build time to prevent the unintentional missing leaked to the build:

    public void CheckMultiColumnListViewBlockOnly()
    {
        string[] uxmlGuids = AssetDatabase.FindAssets("t:VisualTreeAsset");
        foreach (var uxmlGuid in uxmlGuids)
        {
            var assetPath = AssetDatabase.GUIDToAssetPath(uxmlGuid);

            if (!assetPath.StartsWith("Assets/"))
                continue;

            VisualTreeAsset vta = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(assetPath);

            var el = vta.CloneTree();
            var multiColumnListViews = el.Query<MultiColumnListView>().ToList();
            if (multiColumnListViews.Count > 0)
            {
                foreach (var mclv in multiColumnListViews)
                {
                    foreach (var col in mclv.columns)
                    {
                        if (col.cellTemplate == null)
                        {
                            throw new BuildFailedException($"cellTemplate missing: col.title={col.title}, mclv.name={mclv.name}, vta.name={vta.name} (assetPath={assetPath}, uxmlGuid={uxmlGuid})");
                        }
                    }
                }
            }
        }
    }

If you want to investigate it, try to build my open-source game:

A fresh build without the cache and repairs mentioned earlier will likely fail due to the checks I have enforced. Then you can investigate why this happens.