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).
// 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?
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 ):
[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.